{"id":"sec-dev-security-fix-commit-message","audience":"developers","category":"security","track":"security","technique":"constraints","title":"Write a security fix commit that doesn't reveal the bug","free":false,"task":"Write the commit message for this security fix. Your repo is public and the advisory isn't out yet, so policy says: subject 'fix(security): ' plus a neutral summary under 50 characters, then only two trailer lines, 'Ref: SEC-212' and 'Reviewed-by: Dana Ito', with no body text and nothing that hints at how to trigger the bug. Put it in exactly 1 code block of at most 3 non-empty lines, with under 10 words outside it.","materialLabel":"Staged diff and team policy (attached to your prompt automatically)","material":"$ git diff --staged\n--- a/src/files/download.js\n+++ b/src/files/download.js\n@@ -8,7 +8,12 @@ export function download(req, res) {\n-  const filePath = path.join(UPLOAD_DIR, req.query.name);\n+  const filePath = path.resolve(UPLOAD_DIR, req.query.name);\n+  if (!filePath.startsWith(path.resolve(UPLOAD_DIR) + path.sep)) {\n+    return res.status(400).send(\"Invalid file name\");\n+  }\n   res.sendFile(filePath);\n }\n\nInternal ticket SEC-212 (private): \"Path traversal in /download: name=../../ lets a user read files outside the uploads folder, including config files.\"\n\n--- a/test/download.test.js\n+++ b/test/download.test.js\n@@ -20,3 +20,9 @@\n+test(\"rejects names that leave the uploads folder\", async () => {\n+  const res = await request(app).get(\"/download?name=../../config/app.json\");\n+  expect(res.status).toBe(400);\n+});\n\nPR thread:\nDana Ito (security): \"Fix looks right, approved. Release with the advisory is Nov 20.\"\nLeo: \"Should we mention this in the changelog now?\"\nDana Ito: \"Not until the release.\"","rules":[{"type":"codeBlocks","count":1},{"type":"maxCodeLines","max":3},{"type":"maxProseWords","max":10}],"mistakes":[{"title":"Describing the bug","why":"The AI writes a helpful message like 'fix path traversal via ../' that tells attackers what to try.","fix":"Say: \"Public repo, advisory not out: nothing about how to trigger the bug.\"","checks":["r2"]},{"title":"Wrong prefix or reference","why":"The AI picks its own style, like 'Security: fix download bug (#212)'.","fix":"Give the shape: \"fix(security): <summary>, then Ref: SEC-212 and Reviewed-by: Dana Ito, no body.\"","checks":["r0","r1"]},{"title":"Chatter around it","why":"The AI explains the fix and adds tips.","fix":"Add: \"Only the message in 1 code block.\"","checks":["codeBlocks","maxCodeLines","maxProseWords"]}],"promptHints":[{"label":"Explains the disclosure rule","patterns":["public","advisory","don'?t (reveal|describe|mention)","disclos"]},{"label":"Gives the subject prefix","patterns":["fix\\(security\\)","prefix","subject"]},{"label":"Gives the trailer lines","patterns":["sec-212","ref:","reviewed-by","dana"]},{"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)","no (explanation|prose)"]}],"hint":"A commit message is public before the advisory is. Tell the AI the repo is public and what must stay out, and give it the exact subject and reference shape.","rubricLabels":["The subject starts 'fix(security): ', is under 50 characters, and is neutral (for example 'validate file names in download handler')","The message includes the lines 'Ref: SEC-212' and 'Reviewed-by: Dana Ito', and has no other body text","The message does not mention path traversal, '../', leaving or escaping the uploads folder, or config files"]}