DPDP technical safeguards check
Summary
The account was checked against 25 baseline controls covering identity, logging, data, network and secrets, using read-only access only. It scores 31/100 (grade F). The most urgent finding: S3 Bucket acme-demo-uploads has public access due to bucket policy (DA-02, critical). Public buckets are found by automated scanners within hours. Nothing was changed in the account. Every fix below is code or a command for you to review and apply; a retest scan confirms it.
Top risks
| Severity | Control | What we found | First step |
|---|---|---|---|
| critical | DA-02 No bucket is public | S3 Bucket acme-demo-uploads has public access due to bucket policy. (acme-demo-uploads) |
aws s3api put-public-access-block --bucket <bucket> --public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true |
| critical | NC-01 No SSH, RDP or database port is open to the whole internet | Security group api (sg-1c5d8088dba90bc1a) has SSH port 22 open to the Internet. (sg-1c5d8088dba90bc1a) |
aws ec2 revoke-security-group-ingress --group-id <sg> --protocol tcp --port 22 --cidr 0.0.0.0/0 |
| critical | SP-01 No secrets in Lambda variables, EC2 user data or launch templates | Potential secret found in Lambda function acme-invoice-mailer variables -> SMTP Credentials in variable SMTP_PASSWORD, Generic Password in variable SMTP_PASSWORD. (acme-invoice-mailer) |
Move each value to Secrets Manager or SSM Parameter Store (SecureString), read it at runtime, then rotate it - it must be treated as exposed. |
| high | ID-02 Every console user has MFA | User priya.sharma has Console Password enabled but MFA disabled. (priya.sharma) |
aws iam list-virtual-mfa-devices # find users without a device, then enable MFA for each, or move people to IAM Identity Center |
| high | ID-05 Full administrator rights are limited to a break-glass role | AWS policy AdministratorAccess is attached and allows '*:*' administrative privileges. (AdministratorAccess) |
aws iam list-entities-for-policy --policy-arn arn:aws:iam::aws:policy/AdministratorAccess |
DPDP technical safeguards at a glance
| Safeguard area | Controls | Status |
|---|---|---|
| Encryption, masking and secrets | DA-01, DA-03, DA-04, SP-01, SP-02 |
3 failing |
| Access control | ID-01, ID-02, ID-03, ID-04, ID-05, ID-06, ID-07, DA-01, DA-02, DA-04, DA-05, NC-01, NC-02, NC-03, NC-04, SP-03 |
8 failing |
| Logging and monitoring (logs kept at least one year) | LD-01, LD-03, LD-04 |
2 failing |
| Backups and continuity | DA-04 |
no failures |
| Breach detection and 72-hour response | LD-01, LD-02, LD-05 |
1 failing |
| Tested restore within the last 12 months | manual | ask for evidence (service S4 runs a timed restore drill) |
| A written 72-hour breach runbook | manual | template attached (docs/dpdp/breach-runbook-72h.md) |
All controls
Identity and access
The root user can do everything, including closing the account. A stolen root password or key is a total loss.
Passwords get phished and reused. MFA stops most account takeovers.
Evidence (1)
| Resource | Region | Finding |
|---|---|---|
arn:aws:iam::123456789012:user/priya.sharma | ap-south-1 | User priya.sharma has Console Password enabled but MFA disabled. |
How to fix
aws iam list-virtual-mfa-devices # find users without a device, then enable MFA for each, or move people to IAM Identity Center
Long-lived keys leak through laptops, CI logs and git history. Datadog found active keys over a year old at 59% of IAM users.
Permissions attached user by user drift and are never reviewed. Groups, roles and IAM Identity Center keep access auditable.
Evidence (1)
| Resource | Region | Finding |
|---|---|---|
arn:aws:iam::123456789012:user/ci-deploy | ap-south-1 | User ci-deploy has the policy AdministratorAccess attached. |
How to fix
aws iam detach-user-policy --user-name <user> --policy-arn <arn> # after adding the user to a group with the same rights
Every identity with AdministratorAccess is a way to lose the whole account. Most teams need two or three, not ten.
Evidence (1)
| Resource | Region | Finding |
|---|---|---|
arn:aws:iam::aws:policy/AdministratorAccess | ap-south-1 | AWS policy AdministratorAccess is attached and allows '*:*' administrative privileges. |
How to fix
aws iam list-entities-for-policy --policy-arn arn:aws:iam::aws:policy/AdministratorAccess
Only matters for IAM users with console access, but auditors and customer questionnaires ask for it.
It flags buckets, roles and keys shared with other accounts or the public - for free.
Logging and detection
Without CloudTrail there is no record of who did what - no investigation, and no basis for a breach report.
GuardDuty spots stolen credentials, crypto-mining and unusual API calls. Costs a few dollars a month for small accounts.
Evidence (1)
| Resource | Region | Finding |
|---|---|---|
arn:aws:guardduty:ap-south-1:123456789012:detector/unknown | ap-south-1 | GuardDuty is not enabled. |
How to fix
module.security_baseline: guardduty = trueaws guardduty create-detector --enable --finding-publishing-frequency FIFTEEN_MINUTES
Config keeps a history of how each resource was configured - the evidence auditors and investigators ask for.
Evidence (1)
| Resource | Region | Finding |
|---|---|---|
arn:aws:config:ap-south-1:123456789012:recorder | ap-south-1 | AWS Config recorder 123456789012 is disabled. |
How to fix
module.security_baseline: config_recorder = trueLogs kept for days or weeks are gone when an incident is found months later. One year is the minimum many customers - and India's DPDP Rules - expect for security logs. ('Never expire' passes here; the cost check LOGS-001 flags its price.)
Evidence (1)
| Resource | Region | Finding |
|---|---|---|
arn:aws:logs:ap-south-1:123456789012:log-group:/acme/api:* | ap-south-1 | Log Group /acme/api has less than 365 days retention period (7 days). |
How to fix
bash aws-foundation/fix-pack/scripts/set-log-retention.sh --days 365 # dry run first; add --apply to change
A stolen key used for crypto-mining shows up first on the bill. Budgets with email alerts are free.
Data protection
One account-wide switch stops any bucket from being made public by mistake - the cause of many data leaks.
Public buckets are found by automated scanners within hours.
Evidence (1)
| Resource | Region | Finding |
|---|---|---|
arn:aws:s3:::acme-demo-uploads | ap-south-1 | S3 Bucket acme-demo-uploads has public access due to bucket policy. |
How to fix
aws s3api put-public-access-block --bucket <bucket> --public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true # if the bucket serves a website, put CloudFront with origin access control in front instead
Default encryption is free and protects disks, snapshots and buckets that get copied or shared by mistake.
Evidence (1)
| Resource | Region | Finding |
|---|---|---|
arn:aws:ec2:ap-south-1:123456789012:volume | ap-south-1 | EBS Default Encryption is not activated. |
How to fix
module.security_baseline: ebs_encryption_by_default = trueaws ec2 enable-ebs-encryption-by-default --region <region>
An RDS instance reachable from the internet, without backups, is one mistake away from a data leak or permanent loss.
A public EBS or RDS snapshot hands a full copy of the disk or database to anyone.
Network and compute
Open admin and database ports are scanned constantly; one weak password or unpatched service is enough.
Evidence (1)
| Resource | Region | Finding |
|---|---|---|
arn:aws:ec2:ap-south-1:123456789012:security-group/sg-1c5d8088dba90bc1a | ap-south-1 | Security group api (sg-1c5d8088dba90bc1a) has SSH port 22 open to the Internet. |
How to fix
aws ec2 revoke-security-group-ingress --group-id <sg> --protocol tcp --port 22 --cidr 0.0.0.0/0 # use SSM Session Manager (no open port) or a VPN/allow-list instead
Resources launched without a chosen group land in the default one; it should block everything.
IMDSv1 lets an SSRF bug in a web app read the instance's cloud credentials (the Capital One breach). Datadog found IMDSv2 enforced on only 49% of instances.
Evidence (1)
| Resource | Region | Finding |
|---|---|---|
arn:aws:ec2:ap-south-1:123456789012:instance/i-2d70a6f89d6a8d1bd | ap-south-1 | EC2 Instance i-2d70a6f89d6a8d1bd has IMDSv2 disabled or not required. |
How to fix
module.security_baseline: ec2_imdsv2_default = true # new instancesbash aws-foundation/fix-pack/scripts/require-imdsv2.sh --regions <region> # dry run lists instances; --apply after testing one aws ec2 modify-instance-metadata-options --instance-id <id> --http-tokens required --http-put-response-hop-limit 2
Every public instance is attack surface (and costs $3.65 a month per IPv4 address). Most belong behind a load balancer.
Evidence (1)
| Resource | Region | Finding |
|---|---|---|
arn:aws:ec2:ap-south-1:123456789012:instance/i-2d70a6f89d6a8d1bd | ap-south-1 | EC2 Instance i-2d70a6f89d6a8d1bd has a Public IP: 54.214.72.161 (ec2-54-214-72-161.ap-south-1.compute.amazonaws.com). |
How to fix
Secrets and pipelines
Anyone with read-only access - including auditors and many SaaS tools - can read these fields.
Evidence (1)
| Resource | Region | Finding |
|---|---|---|
arn:aws:lambda:ap-south-1:123456789012:function:acme-invoice-mailer | ap-south-1 | Potential secret found in Lambda function acme-invoice-mailer variables -> SMTP Credentials in variable SMTP_PASSWORD, Generic Password in variable SMTP_PASSWORD. |
How to fix
A secret that never changes stays valid after every leak.
Evidence (1)
| Resource | Region | Finding |
|---|---|---|
arn:aws:secretsmanager:ap-south-1:123456789012:secret:acme/prod/db-zTNKUh | ap-south-1 | SecretsManager secret acme/prod/db has rotation disabled. |
How to fix
aws secretsmanager rotate-secret --secret-id <id> --rotation-lambda-arn <arn> --rotation-rules AutomaticallyAfterDays=90
Keys stored in CI were stolen in the tj-actions, Trivy and Checkmarx incidents. OIDC tokens expire in minutes.
Evidence (1)
| Resource | Region | Finding |
|---|---|---|
arn:aws:iam::123456789012:user/ci-deploy | global | IAM user 'ci-deploy' looks like a CI/CD identity and has an active access key (created 2026-11-02); replace it with an OIDC role |
How to fix
gha-hardening-kit/terraform/github-oidc-role (service S2)Scanning catches known vulnerabilities before deployment; immutable tags stop a pushed image being silently replaced.
Evidence (3)
| Resource | Region | Finding |
|---|---|---|
arn:aws:ecr:ap-south-1:123456789012:registry/123456789012 | ap-south-1 | ECR registry 123456789012 has BASIC scanning without automated scanning enabled. |
arn:aws:ecr:ap-south-1:123456789012:repository/acme/api | ap-south-1 | ECR repository acme/api has scan on push disabled. |
arn:aws:ecr:ap-south-1:123456789012:repository/acme/api | ap-south-1 | Repository acme/api does not have immutability configured. |
How to fix
module.security_baseline: ecr_scan_on_push = trueaws ecr put-image-tag-mutability --repository-name <repo> --image-tag-mutability IMMUTABLE
Method and limits
- Read-only access: a cross-account role with the AWS-managed
SecurityAuditandViewOnlyAccesspolicies, a few extra read permissions, and an explicit deny on reading data (S3 objects, database rows, secret values, log events). The account's own CloudTrail records every call. - Engine: Prowler 5.47.0 (open source, Apache-2.0) running 48 curated checks, plus two native checks for spend alerts and CI/CD credentials. Each finding was reviewed by a person before delivery.
- Score: each evaluated control counts by severity (critical 10, high 6, medium 3, low 1). Controls with no matching resources, or that could not be evaluated, are left out of the score and shown as coverage instead.
- Findings reflect the configuration at the time of the scan. A baseline check is not a penetration test and not a guarantee that the account cannot be breached.
- This is a technical readiness review, not legal advice and not a certification of compliance with the DPDP Act or Rules.
- Not evaluated in the simulator (ID-01, ID-07, DA-01): it has no root user, IAM Access Analyzer or account-level S3 settings. A scan of a real account evaluates them.