{"id":"sec-it-cloud-policy-least-privilege","audience":"it-security","category":"security","track":"security","technique":"constraints","title":"Tighten an over-broad cloud access policy","free":false,"task":"The reporting app's cloud policy grants far more than it needs. Rewrite it so it grants only what the app does today, per the notes. Your team's convention: one statement per line, and each statement gets a Sid from this list: ReadSalesExports, WriteFinanceReports, QuerySalesDb. Put the policy in exactly 1 code block of at most 12 lines, with under 20 words outside it.","materialLabel":"Current policy and app notes (attached to your prompt automatically)","material":"Current policy for role \"reporting-app\" (cloud: example provider, JSON format)\n{\n  \"Version\": \"2024-01\",\n  \"Statements\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\"storage:*\"],\n      \"Resource\": [\"bucket:*\"]\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\"db:Query\", \"db:DeleteTable\", \"db:CreateUser\"],\n      \"Resource\": [\"db:sales-prod\"]\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\"iam:*\"],\n      \"Resource\": [\"*\"]\n    }\n  ]\n}\n\nApp notes (from the reporting team, Nov 2026):\n- The app reads CSV files from the bucket \"sales-exports\" (action storage:GetObject).\n- It writes finished PDF reports to the \"reports/\" folder of the bucket \"finance-reports\" (action storage:PutObject, resource bucket:finance-reports/reports/*).\n- It runs read-only queries on the sales-prod database (action db:Query).\n- It never creates users or deletes tables. The iam:* line was added \"temporarily\" during setup in 2025.\n- It also needs to list the files in sales-exports (storage:ListBucket).\n- Until June it also copied old reports to the bucket \"archive-2019\" (storage:PutObject). That job was retired in June.","rules":[{"type":"codeBlocks","count":1},{"type":"maxCodeLines","max":12},{"type":"maxProseWords","max":20}],"mistakes":[{"title":"Not giving what the app needs","why":"The AI guesses permissions and often keeps broad ones 'for flexibility'.","fix":"Say: \"Grant only the actions in the app notes, nothing else.\"","checks":["r1"]},{"title":"Leaving a wildcard","why":"The AI narrows some lines but keeps a * somewhere.","fix":"Add: \"No wildcard actions and no iam permissions.\"","checks":["r0"]},{"title":"Ignoring the team convention","why":"The AI pretty-prints each statement over many lines and leaves out Sids.","fix":"Say: \"One statement per line, with Sids ReadSalesExports, WriteFinanceReports, QuerySalesDb.\"","checks":["r0","r2","maxCodeLines"]},{"title":"A long explanation","why":"The AI adds paragraphs on least privilege around the code.","fix":"Limit it: \"One code block, one short sentence outside it.\"","checks":["codeBlocks","maxProseWords"]},{"title":"Keeping retired access","why":"The AI keeps the archive bucket because it appears in the notes.","fix":"Add: \"Only what the app does today. The archive job is retired.\"","checks":["r1"]}],"promptHints":[{"label":"Grants only what's listed","patterns":["only (the )?(actions|permissions|what)","app notes","least privilege","nothing else"]},{"label":"Bans wildcards","patterns":["wildcard","\\*","no iam"]},{"label":"Gives the team convention","patterns":["sid","one statement per line","single line","readsalesexports"]},{"label":"Asks for one code block","patterns":["(one|1|single) code block","code block"]},{"label":"Limits the explanation","patterns":["\\d+\\s*words","short (note|explanation)","one (line|sentence)"]}],"hint":"Least privilege means listing exactly what the app does. Point the AI at the app notes, ban wildcards, and keep the output to one short code block.","rubricLabels":["There are exactly 3 statements with the Sids ReadSalesExports, WriteFinanceReports and QuerySalesDb (exact spelling)","It grants storage:GetObject and storage:ListBucket on sales-exports, storage:PutObject on finance-reports/reports/*, and db:Query on sales-prod, and nothing else (no wildcards, no iam, no db:DeleteTable or db:CreateUser, nothing for archive-2019)","Each statement is written on a single line"]}