{"owner":"HKUDS","repo":"DeepCode","hasSkills":true,"totalSkillsCount":32,"totalTokensCount":127394,"categories":["anthropic-skill"],"hasMcp":false,"mcpConfig":null,"found":["core/skills/builtin/UPSTREAM_SOURCES.json","core/skills/builtin/frontend-design/SKILL.md","core/skills/builtin/mcp-builder/SKILL.md","core/skills/builtin/mcp-builder/reference/evaluation.md","core/skills/builtin/mcp-builder/reference/mcp_best_practices.md","core/skills/builtin/mcp-builder/reference/node_mcp_server.md","core/skills/builtin/mcp-builder/reference/python_mcp_server.md","core/skills/builtin/review-agent/SKILL.md","core/skills/builtin/review-agent/agents/openai.yaml","core/skills/builtin/security-best-practices/SKILL.md","core/skills/builtin/security-best-practices/agents/openai.yaml","core/skills/builtin/security-best-practices/references/golang-general-backend-security.md","core/skills/builtin/security-best-practices/references/javascript-express-web-server-security.md","core/skills/builtin/security-best-practices/references/javascript-general-web-frontend-security.md","core/skills/builtin/security-best-practices/references/javascript-jquery-web-frontend-security.md","core/skills/builtin/security-best-practices/references/javascript-typescript-nextjs-web-server-security.md","core/skills/builtin/security-best-practices/references/javascript-typescript-react-web-frontend-security.md","core/skills/builtin/security-best-practices/references/javascript-typescript-vue-web-frontend-security.md","core/skills/builtin/security-best-practices/references/python-django-web-server-security.md","core/skills/builtin/security-best-practices/references/python-fastapi-web-server-security.md","core/skills/builtin/security-best-practices/references/python-flask-web-server-security.md","core/skills/builtin/security-ownership-map/SKILL.md","core/skills/builtin/security-ownership-map/agents/openai.yaml","core/skills/builtin/security-ownership-map/references/neo4j-import.md","core/skills/builtin/security-threat-model/SKILL.md","core/skills/builtin/security-threat-model/agents/openai.yaml","core/skills/builtin/security-threat-model/references/prompt-template.md","core/skills/builtin/security-threat-model/references/security-controls-and-assets.md","core/skills/builtin/skill-creator/SKILL.md","core/skills/builtin/skill-creator/agents/openai.yaml","core/skills/builtin/skill-creator/references/openai_yaml.md","core/skills/builtin/webapp-testing/SKILL.md"],"skills":{"core/skills/builtin/UPSTREAM_SOURCES.json":"{\n  \"schemaVersion\": 1,\n  \"skills\": {\n    \"frontend-design\": {\n      \"repository\": \"https://github.com/anthropics/skills\",\n      \"revision\": \"f17010c9bb483898c1d9c9f42dde2b3a98889434\",\n      \"path\": \"skills/frontend-design\"\n    },\n    \"mcp-builder\": {\n      \"repository\": \"https://github.com/anthropics/skills\",\n      \"revision\": \"f17010c9bb483898c1d9c9f42dde2b3a98889434\",\n      \"path\": \"skills/mcp-builder\"\n    },\n    \"review-agent\": {\n      \"repository\": \"https://github.com/openai/codex\",\n      \"revision\": \"4ef836f883c38ba6d39e6920f335ce6452b7de33\",\n      \"path\": \"codex-rs/skills/src/assets/samples/review-agent\"\n    },\n    \"security-best-practices\": {\n      \"repository\": \"https://github.com/openai/skills\",\n      \"revision\": \"49f948faa9258a0c61caceaf225e179651397431\",\n      \"path\": \"skills/.curated/security-best-practices\"\n    },\n    \"security-ownership-map\": {\n      \"repository\": \"https://github.com/openai/skills\",\n      \"revision\": \"49f948faa9258a0c61caceaf225e179651397431\",\n      \"path\": \"skills/.curated/security-ownership-map\"\n    },\n    \"security-threat-model\": {\n      \"repository\": \"https://github.com/openai/skills\",\n      \"revision\": \"49f948faa9258a0c61caceaf225e179651397431\",\n      \"path\": \"skills/.curated/security-threat-model\"\n    },\n    \"skill-creator\": {\n      \"repository\": \"https://github.com/openai/skills\",\n      \"revision\": \"49f948faa9258a0c61caceaf225e179651397431\",\n      \"path\": \"skills/.system/skill-creator\"\n    },\n    \"webapp-testing\": {\n      \"repository\": \"https://github.com/anthropics/skills\",\n      \"revision\": \"f17010c9bb483898c1d9c9f42dde2b3a98889434\",\n      \"path\": \"skills/webapp-testing\"\n    }\n  }\n}\n","core/skills/builtin/frontend-design/SKILL.md":"---\nname: frontend-design\ndescription: Guidance for distinctive, intentional visual design when building new UI or reshaping an existing one. Helps with aesthetic direction, typography, and making choices that don't read as templated defaults.\nlicense: Complete terms in LICENSE.txt\n---\n\n# Frontend Design\n\nApproach this as the design lead at a small studio known for giving every client a visual identity that could not be mistaken for anyone else's. This client has already rejected proposals that felt templated, and is paying for a distinctive point of view: make deliberate, opinionated choices about palette, typography, and layout that are specific to this brief, and take one real aesthetic risk you can justify.\n\n## Ground it in the subject\n\nIf the brief does not pin down what the product or subject is, pin it yourself before designing: name one concrete subject, its audience, and the page's single job, and state your choice. If there's any information in your memory about the human's preferences, context about what they're building, or designs you've made before – use that as a hint. The subject's own world, its materials, instruments, artifacts, and vernacular, is where distinctive choices come from. Build with the brief's real content and subject matter throughout.\n\n## Design principles\n\nFor web designs, the hero is a thesis. Open with the most characteristic thing in the subject's world, in whatever form makes sense for it: a headline, an image, an animation, a live demo, an interactive moment. Be deliberate with your choice: a big number with a small label, supporting stats, and a gradient accent is the template answer, only use if that's truly the best option.\n\nTypography carries the personality of the page. Pair the display and body faces deliberately, not the same families you would reach for on any other project, and set a clear type scale with intentional weights, widths, and spacing. Make the type treatment itself a memorable part of the design, not a neutral delivery vehicle for the content.\n\nStructure is information. Structural devices, numbering, eyebrows, dividers, labels, should encode something true about the content, not decorate it. Many generic designs use numbered markers (01 / 02 / 03), but that's only appropriate if the content actually is a sequence - like a real process or a typed timeline where order carries information the reader needs. Question if choices like numbered markers actually make sense before incorporating them.\n\nLeverage motion deliberately. Think about where and if animation can serve the subject: a page-load sequence, a scroll-triggered reveal, hover micro-interactions, ambient atmosphere. An orchestrated moment usually lands harder than scattered effects; choose what the direction calls for. However, sometimes less is more, and extra animation contributes to the feeling that the design is AI-generated.\n\nMatch complexity to the vision. Maximalist directions need elaborate execution; minimal directions need precision in spacing, type, and detail. Elegance is executing the chosen vision well.\n\nConsider written content carefully. Often a design brief may not contain real content, and it's up to you to come up with copy. Copy can make a design feel as templated as the design itself. See the below section on writing for more guidance.\n\n## Process: brainstorm, explore, plan, critique, build, critique again\n\nFor calibration: AI-generated design right now clusters around three looks: (1) a warm cream background (near #F4F1EA) with a high-contrast serif display and a terracotta accent; (2) a near-black background with a single bright acid-green or vermilion accent; (3) a broadsheet-style layout with hairline rules, zero border-radius, and dense newspaper-like columns. All three are legitimate for some briefs, but they are defaults rather than choices, and they appear regardless of subject. Where the brief pins down a visual direction, follow it exactly — the brief's own words always win, including when it asks for one of these looks. Where it leaves an axis free, don't spend that freedom on one of these defaults. Just like a human designer who's hired, there's often a careful balance between doing what you're good at and taking each project as a chance to experiment and learn.\n\nWork in two passes. First, brainstorm a short design plan based on the human's design brief: create a compact token system with color, type, layout, and signature. Color: describe the palette as 4–6 named hex values. Type: the typefaces for 2+ roles (a characterful display face that's used with restraint, a complementary body face, and a utility face for captions or data if needed). Layout: a layout concept, using one-sentence prose descriptions and ASCII wireframes to ideate and compare. Signature: the single unique element this page will be remembered by that embodies the brief in an appropriate way.\n\nThen review that plan against the brief before building: if any part of it reads like the generic default you would produce for any similar page (work through a similar prompt to see if you arrive somewhere similar) rather than a choice made for this specific brief — revise that part, say what you changed and why. Only after you've confirmed the relative uniqueness of your design plan should you start to write the code, following the revised plan exactly and deriving every color and type decision from it.\n\nWhen writing the code, be careful of structuring your CSS selector specificities. It's easy to generate CSS classes that cancel each other out (especially with a type-based selector like .section and a element-based selector like .cta). This can happen often with paddings/margins between sections.\n\nTry to do a lot of this planning and iteration in your thinking, and only show ideas to the user when you have higher confidence it'll delight them.\n\n## Restraint and self-critique\n\nSpend your boldness in one place. Let the signature element be the one memorable thing, keep everything around it quiet and disciplined, and cut any decoration that does not serve the brief. Not taking a risk can be a risk itself! Build to a quality floor without announcing it: responsive down to mobile, visible keyboard focus, reduced motion respected. Critique your own work as you build, taking screenshots if your environment supports it – a picture is worth 1000 tokens. Consider Chanel's advice: before leaving the house, take a look in the mirror and remove one accessory. Human creators have memory and always try to do something new, so if you have a space to quickly jot down notes about what you've tried, it can help you in future passes.\n\n## More on writing in design\n\nWords appear in a design for one reason: to make it easier to understand, and therefore easier to use. They are design material, not decoration. Bring the same intentionality to copy that you would bring to spacing and color. Before writing anything, ask what the design needs to say, and how it can best be said to help the person navigate the experience.\n\nWrite from the end user's side of the screen. Name things by what people control and recognize, never by how the system is built. A person manages notifications, not webhook config. Describe what something does in plain terms rather than selling it. Being specific is always better than being clever.\n\nUse active voice as default. A control should say exactly what happens when it's used: \"Save changes,\" not \"Submit.\" An action keeps the same name through the whole flow, so the button that says \"Publish\" produces a toast that says \"Published.\" The vocabulary of an interface is the signposting for someone navigating the product. Cohesion and consistency are how people learn their way around.\n\nTreat failure and emptiness as moments for direction, not mood. Explain what went wrong and how to fix it, in the interface's voice rather than a person's. Errors don't apologize, and they are never vague about what happened. An empty screen is an invitation to act.\n\nKeep the register conversational and tuned: plain verbs, sentence case, no filler, with tone matched to the brand and the audience. Let each element do exactly one job. A label labels, an example demonstrates, and nothing quietly does double duty.\n","core/skills/builtin/mcp-builder/SKILL.md":"---\nname: mcp-builder\ndescription: Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).\nlicense: Complete terms in LICENSE.txt\n---\n\n# MCP Server Development Guide\n\n## Overview\n\nCreate MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. The quality of an MCP server is measured by how well it enables LLMs to accomplish real-world tasks.\n\n---\n\n# Process\n\n## 🚀 High-Level Workflow\n\nCreating a high-quality MCP server involves four main phases:\n\n### Phase 1: Deep Research and Planning\n\n#### 1.1 Understand Modern MCP Design\n\n**API Coverage vs. Workflow Tools:**\nBalance comprehensive API endpoint coverage with specialized workflow tools. Workflow tools can be more convenient for specific tasks, while comprehensive coverage gives agents flexibility to compose operations. Performance varies by client—some clients benefit from code execution that combines basic tools, while others work better with higher-level workflows. When uncertain, prioritize comprehensive API coverage.\n\n**Tool Naming and Discoverability:**\nClear, descriptive tool names help agents find the right tools quickly. Use consistent prefixes (e.g., `github_create_issue`, `github_list_repos`) and action-oriented naming.\n\n**Context Management:**\nAgents benefit from concise tool descriptions and the ability to filter/paginate results. Design tools that return focused, relevant data. Some clients support code execution which can help agents filter and process data efficiently.\n\n**Actionable Error Messages:**\nError messages should guide agents toward solutions with specific suggestions and next steps.\n\n#### 1.2 Study MCP Protocol Documentation\n\n**Navigate the MCP specification:**\n\nStart with the sitemap to find relevant pages: `https://modelcontextprotocol.io/sitemap.xml`\n\nThen fetch specific pages with `.md` suffix for markdown format (e.g., `https://modelcontextprotocol.io/specification/draft.md`).\n\nKey pages to review:\n- Specification overview and architecture\n- Transport mechanisms (streamable HTTP, stdio)\n- Tool, resource, and prompt definitions\n\n#### 1.3 Study Framework Documentation\n\n**Recommended stack:**\n- **Language**: TypeScript (high-quality SDK support and good compatibility in many execution environments e.g. MCPB. Plus AI models are good at generating TypeScript code, benefiting from its broad usage, static typing and good linting tools)\n- **Transport**: Streamable HTTP for remote servers, using stateless JSON (simpler to scale and maintain, as opposed to stateful sessions and streaming responses). stdio for local servers.\n\n**Load framework documentation:**\n\n- **MCP Best Practices**: [📋 View Best Practices](./reference/mcp_best_practices.md) - Core guidelines\n\n**For TypeScript (recommended):**\n- **TypeScript SDK**: Use WebFetch to load `https://raw.githubusercontent.com/modelcontextprotocol/typescript-sdk/main/README.md`\n- [⚡ TypeScript Guide](./reference/node_mcp_server.md) - TypeScript patterns and examples\n\n**For Python:**\n- **Python SDK**: Use WebFetch to load `https://raw.githubusercontent.com/modelcontextprotocol/python-sdk/main/README.md`\n- [🐍 Python Guide](./reference/python_mcp_server.md) - Python patterns and examples\n\n#### 1.4 Plan Your Implementation\n\n**Understand the API:**\nReview the service's API documentation to identify key endpoints, authentication requirements, and data models. Use web search and WebFetch as needed.\n\n**Tool Selection:**\nPrioritize comprehensive API coverage. List endpoints to implement, starting with the most common operations.\n\n---\n\n### Phase 2: Implementation\n\n#### 2.1 Set Up Project Structure\n\nSee language-specific guides for project setup:\n- [⚡ TypeScript Guide](./reference/node_mcp_server.md) - Project structure, package.json, tsconfig.json\n- [🐍 Python Guide](./reference/python_mcp_server.md) - Module organization, dependencies\n\n#### 2.2 Implement Core Infrastructure\n\nCreate shared utilities:\n- API client with authentication\n- Error handling helpers\n- Response formatting (JSON/Markdown)\n- Pagination support\n\n#### 2.3 Implement Tools\n\nFor each tool:\n\n**Input Schema:**\n- Use Zod (TypeScript) or Pydantic (Python)\n- Include constraints and clear descriptions\n- Add examples in field descriptions\n\n**Output Schema:**\n- Define `outputSchema` where possible for structured data\n- Use `structuredContent` in tool responses (TypeScript SDK feature)\n- Helps clients understand and process tool outputs\n\n**Tool Description:**\n- Concise summary of functionality\n- Parameter descriptions\n- Return type schema\n\n**Implementation:**\n- Async/await for I/O operations\n- Proper error handling with actionable messages\n- Support pagination where applicable\n- Return both text content and structured data when using modern SDKs\n\n**Annotations:**\n- `readOnlyHint`: true/false\n- `destructiveHint`: true/false\n- `idempotentHint`: true/false\n- `openWorldHint`: true/false\n\n---\n\n### Phase 3: Review and Test\n\n#### 3.1 Code Quality\n\nReview for:\n- No duplicated code (DRY principle)\n- Consistent error handling\n- Full type coverage\n- Clear tool descriptions\n\n#### 3.2 Build and Test\n\n**TypeScript:**\n- Run `npm run build` to verify compilation\n- Test with MCP Inspector: `npx @modelcontextprotocol/inspector`\n\n**Python:**\n- Verify syntax: `python -m py_compile your_server.py`\n- Test with MCP Inspector\n\nSee language-specific guides for detailed testing approaches and quality checklists.\n\n---\n\n### Phase 4: Create Evaluations\n\nAfter implementing your MCP server, create comprehensive evaluations to test its effectiveness.\n\n**Load [✅ Evaluation Guide](./reference/evaluation.md) for complete evaluation guidelines.**\n\n#### 4.1 Understand Evaluation Purpose\n\nUse evaluations to test whether LLMs can effectively use your MCP server to answer realistic, complex questions.\n\n#### 4.2 Create 10 Evaluation Questions\n\nTo create effective evaluations, follow the process outlined in the evaluation guide:\n\n1. **Tool Inspection**: List available tools and understand their capabilities\n2. **Content Exploration**: Use READ-ONLY operations to explore available data\n3. **Question Generation**: Create 10 complex, realistic questions\n4. **Answer Verification**: Solve each question yourself to verify answers\n\n#### 4.3 Evaluation Requirements\n\nEnsure each question is:\n- **Independent**: Not dependent on other questions\n- **Read-only**: Only non-destructive operations required\n- **Complex**: Requiring multiple tool calls and deep exploration\n- **Realistic**: Based on real use cases humans would care about\n- **Verifiable**: Single, clear answer that can be verified by string comparison\n- **Stable**: Answer won't change over time\n\n#### 4.4 Output Format\n\nCreate an XML file with this structure:\n\n```xml\n<evaluation>\n  <qa_pair>\n    <question>Find discussions about AI model launches with animal codenames. One model needed a specific safety designation that uses the format ASL-X. What number X was being determined for the model named after a spotted wild cat?</question>\n    <answer>3</answer>\n  </qa_pair>\n<!-- More qa_pairs... -->\n</evaluation>\n```\n\n---\n\n# Reference Files\n\n## 📚 Documentation Library\n\nLoad these resources as needed during development:\n\n### Core MCP Documentation (Load First)\n- **MCP Protocol**: Start with sitemap at `https://modelcontextprotocol.io/sitemap.xml`, then fetch specific pages with `.md` suffix\n- [📋 MCP Best Practices](./reference/mcp_best_practices.md) - Universal MCP guidelines including:\n  - Server and tool naming conventions\n  - Response format guidelines (JSON vs Markdown)\n  - Pagination best practices\n  - Transport selection (streamable HTTP vs stdio)\n  - Security and error handling standards\n\n### SDK Documentation (Load During Phase 1/2)\n- **Python SDK**: Fetch from `https://raw.githubusercontent.com/modelcontextprotocol/python-sdk/main/README.md`\n- **TypeScript SDK**: Fetch from `https://raw.githubusercontent.com/modelcontextprotocol/typescript-sdk/main/README.md`\n\n### Language-Specific Implementation Guides (Load During Phase 2)\n- [🐍 Python Implementation Guide](./reference/python_mcp_server.md) - Complete Python/FastMCP guide with:\n  - Server initialization patterns\n  - Pydantic model examples\n  - Tool registration with `@mcp.tool`\n  - Complete working examples\n  - Quality checklist\n\n- [⚡ TypeScript Implementation Guide](./reference/node_mcp_server.md) - Complete TypeScript guide with:\n  - Project structure\n  - Zod schema patterns\n  - Tool registration with `server.registerTool`\n  - Complete working examples\n  - Quality checklist\n\n### Evaluation Guide (Load During Phase 4)\n- [✅ Evaluation Guide](./reference/evaluation.md) - Complete evaluation creation guide with:\n  - Question creation guidelines\n  - Answer verification strategies\n  - XML format specifications\n  - Example questions and answers\n  - Running an evaluation with the provided scripts\n","core/skills/builtin/mcp-builder/reference/evaluation.md":"# MCP Server Evaluation Guide\n\n## Overview\n\nThis document provides guidance on creating comprehensive evaluations for MCP servers. Evaluations test whether LLMs can effectively use your MCP server to answer realistic, complex questions using only the tools provided.\n\n---\n\n## Quick Reference\n\n### Evaluation Requirements\n- Create 10 human-readable questions\n- Questions must be READ-ONLY, INDEPENDENT, NON-DESTRUCTIVE\n- Each question requires multiple tool calls (potentially dozens)\n- Answers must be single, verifiable values\n- Answers must be STABLE (won't change over time)\n\n### Output Format\n```xml\n<evaluation>\n   <qa_pair>\n      <question>Your question here</question>\n      <answer>Single verifiable answer</answer>\n   </qa_pair>\n</evaluation>\n```\n\n---\n\n## Purpose of Evaluations\n\nThe measure of quality of an MCP server is NOT how well or comprehensively the server implements tools, but how well these implementations (input/output schemas, docstrings/descriptions, functionality) enable LLMs with no other context and access ONLY to the MCP servers to answer realistic and difficult questions.\n\n## Evaluation Overview\n\nCreate 10 human-readable questions requiring ONLY READ-ONLY, INDEPENDENT, NON-DESTRUCTIVE, and IDEMPOTENT operations to answer. Each question should be:\n- Realistic\n- Clear and concise\n- Unambiguous\n- Complex, requiring potentially dozens of tool calls or steps\n- Answerable with a single, verifiable value that you identify in advance\n\n## Question Guidelines\n\n### Core Requirements\n\n1. **Questions MUST be independent**\n   - Each question should NOT depend on the answer to any other question\n   - Should not assume prior write operations from processing another question\n\n2. **Questions MUST require ONLY NON-DESTRUCTIVE AND IDEMPOTENT tool use**\n   - Should not instruct or require modifying state to arrive at the correct answer\n\n3. **Questions must be REALISTIC, CLEAR, CONCISE, and COMPLEX**\n   - Must require another LLM to use multiple (potentially dozens of) tools or steps to answer\n\n### Complexity and Depth\n\n4. **Questions must require deep exploration**\n   - Consider multi-hop questions requiring multiple sub-questions and sequential tool calls\n   - Each step should benefit from information found in previous questions\n\n5. **Questions may require extensive paging**\n   - May need paging through multiple pages of results\n   - May require querying old data (1-2 years out-of-date) to find niche information\n   - The questions must be DIFFICULT\n\n6. **Questions must require deep understanding**\n   - Rather than surface-level knowledge\n   - May pose complex ideas as True/False questions requiring evidence\n   - May use multiple-choice format where LLM must search different hypotheses\n\n7. **Questions must not be solvable with straightforward keyword search**\n   - Do not include specific keywords from the target content\n   - Use synonyms, related concepts, or paraphrases\n   - Require multiple searches, analyzing multiple related items, extracting context, then deriving the answer\n\n### Tool Testing\n\n8. **Questions should stress-test tool return values**\n   - May elicit tools returning large JSON objects or lists, overwhelming the LLM\n   - Should require understanding multiple modalities of data:\n     - IDs and names\n     - Timestamps and datetimes (months, days, years, seconds)\n     - File IDs, names, extensions, and mimetypes\n     - URLs, GIDs, etc.\n   - Should probe the tool's ability to return all useful forms of data\n\n9. **Questions should MOSTLY reflect real human use cases**\n   - The kinds of information retrieval tasks that HUMANS assisted by an LLM would care about\n\n10. **Questions may require dozens of tool calls**\n    - This challenges LLMs with limited context\n    - Encourages MCP server tools to reduce information returned\n\n11. **Include ambiguous questions**\n    - May be ambiguous OR require difficult decisions on which tools to call\n    - Force the LLM to potentially make mistakes or misinterpret\n    - Ensure that despite AMBIGUITY, there is STILL A SINGLE VERIFIABLE ANSWER\n\n### Stability\n\n12. **Questions must be designed so the answer DOES NOT CHANGE**\n    - Do not ask questions that rely on \"current state\" which is dynamic\n    - For example, do not count:\n      - Number of reactions to a post\n      - Number of replies to a thread\n      - Number of members in a channel\n\n13. **DO NOT let the MCP server RESTRICT the kinds of questions you create**\n    - Create challenging and complex questions\n    - Some may not be solvable with the available MCP server tools\n    - Questions may require specific output formats (datetime vs. epoch time, JSON vs. MARKDOWN)\n    - Questions may require dozens of tool calls to complete\n\n## Answer Guidelines\n\n### Verification\n\n1. **Answers must be VERIFIABLE via direct string comparison**\n   - If the answer can be re-written in many formats, clearly specify the output format in the QUESTION\n   - Examples: \"Use YYYY/MM/DD.\", \"Respond True or False.\", \"Answer A, B, C, or D and nothing else.\"\n   - Answer should be a single VERIFIABLE value such as:\n     - User ID, user name, display name, first name, last name\n     - Channel ID, channel name\n     - Message ID, string\n     - URL, title\n     - Numerical quantity\n     - Timestamp, datetime\n     - Boolean (for True/False questions)\n     - Email address, phone number\n     - File ID, file name, file extension\n     - Multiple choice answer\n   - Answers must not require special formatting or complex, structured output\n   - Answer will be verified using DIRECT STRING COMPARISON\n\n### Readability\n\n2. **Answers should generally prefer HUMAN-READABLE formats**\n   - Examples: names, first name, last name, datetime, file name, message string, URL, yes/no, true/false, a/b/c/d\n   - Rather than opaque IDs (though IDs are acceptable)\n   - The VAST MAJORITY of answers should be human-readable\n\n### Stability\n\n3. **Answers must be STABLE/STATIONARY**\n   - Look at old content (e.g., conversations that have ended, projects that have launched, questions answered)\n   - Create QUESTIONS based on \"closed\" concepts that will always return the same answer\n   - Questions may ask to consider a fixed time window to insulate from non-stationary answers\n   - Rely on context UNLIKELY to change\n   - Example: if finding a paper name, be SPECIFIC enough so answer is not confused with papers published later\n\n4. **Answers must be CLEAR and UNAMBIGUOUS**\n   - Questions must be designed so there is a single, clear answer\n   - Answer can be derived from using the MCP server tools\n\n### Diversity\n\n5. **Answers must be DIVERSE**\n   - Answer should be a single VERIFIABLE value in diverse modalities and formats\n   - User concept: user ID, user name, display name, first name, last name, email address, phone number\n   - Channel concept: channel ID, channel name, channel topic\n   - Message concept: message ID, message string, timestamp, month, day, year\n\n6. **Answers must NOT be complex structures**\n   - Not a list of values\n   - Not a complex object\n   - Not a list of IDs or strings\n   - Not natural language text\n   - UNLESS the answer can be straightforwardly verified using DIRECT STRING COMPARISON\n   - And can be realistically reproduced\n   - It should be unlikely that an LLM would return the same list in any other order or format\n\n## Evaluation Process\n\n### Step 1: Documentation Inspection\n\nRead the documentation of the target API to understand:\n- Available endpoints and functionality\n- If ambiguity exists, fetch additional information from the web\n- Parallelize this step AS MUCH AS POSSIBLE\n- Ensure each subagent is ONLY examining documentation from the file system or on the web\n\n### Step 2: Tool Inspection\n\nList the tools available in the MCP server:\n- Inspect the MCP server directly\n- Understand input/output schemas, docstrings, and descriptions\n- WITHOUT calling the tools themselves at this stage\n\n### Step 3: Developing Understanding\n\nRepeat steps 1 & 2 until you have a good understanding:\n- Iterate multiple times\n- Think about the kinds of tasks you want to create\n- Refine your understanding\n- At NO stage should you READ the code of the MCP server implementation itself\n- Use your intuition and understanding to create reasonable, realistic, but VERY challenging tasks\n\n### Step 4: Read-Only Content Inspection\n\nAfter understanding the API and tools, USE the MCP server tools:\n- Inspect content using READ-ONLY and NON-DESTRUCTIVE operations ONLY\n- Goal: identify specific content (e.g., users, channels, messages, projects, tasks) for creating realistic questions\n- Should NOT call any tools that modify state\n- Will NOT read the code of the MCP server implementation itself\n- Parallelize this step with individual sub-agents pursuing independent explorations\n- Ensure each subagent is only performing READ-ONLY, NON-DESTRUCTIVE, and IDEMPOTENT operations\n- BE CAREFUL: SOME TOOLS may return LOTS OF DATA which would cause you to run out of CONTEXT\n- Make INCREMENTAL, SMALL, AND TARGETED tool calls for exploration\n- In all tool call requests, use the `limit` parameter to limit results (<10)\n- Use pagination\n\n### Step 5: Task Generation\n\nAfter inspecting the content, create 10 human-readable questions:\n- An LLM should be able to answer these with the MCP server\n- Follow all question and answer guidelines above\n\n## Output Format\n\nEach QA pair consists of a question and an answer. The output should be an XML file with this structure:\n\n```xml\n<evaluation>\n   <qa_pair>\n      <question>Find the project created in Q2 2024 with the highest number of completed tasks. What is the project name?</question>\n      <answer>Website Redesign</answer>\n   </qa_pair>\n   <qa_pair>\n      <question>Search for issues labeled as \"bug\" that were closed in March 2024. Which user closed the most issues? Provide their username.</question>\n      <answer>sarah_dev</answer>\n   </qa_pair>\n   <qa_pair>\n      <question>Look for pull requests that modified files in the /api directory and were merged between January 1 and January 31, 2024. How many different contributors worked on these PRs?</question>\n      <answer>7</answer>\n   </qa_pair>\n   <qa_pair>\n      <question>Find the repository with the most stars that was created before 2023. What is the repository name?</question>\n      <answer>data-pipeline</answer>\n   </qa_pair>\n</evaluation>\n```\n\n## Evaluation Examples\n\n### Good Questions\n\n**Example 1: Multi-hop question requiring deep exploration (GitHub MCP)**\n```xml\n<qa_pair>\n   <question>Find the repository that was archived in Q3 2023 and had previously been the most forked project in the organization. What was the primary programming language used in that repository?</question>\n   <answer>Python</answer>\n</qa_pair>\n```\n\nThis question is good because:\n- Requires multiple searches to find archived repositories\n- Needs to identify which had the most forks before archival\n- Requires examining repository details for the language\n- Answer is a simple, verifiable value\n- Based on historical (closed) data that won't change\n\n**Example 2: Requires understanding context without keyword matching (Project Management MCP)**\n```xml\n<qa_pair>\n   <question>Locate the initiative focused on improving customer onboarding that was completed in late 2023. The project lead created a retrospective document after completion. What was the lead's role title at that time?</question>\n   <answer>Product Manager</answer>\n</qa_pair>\n```\n\nThis question is good because:\n- Doesn't use specific project name (\"initiative focused on improving customer onboarding\")\n- Requires finding completed projects from specific timeframe\n- Needs to identify the project lead and their role\n- Requires understanding context from retrospective documents\n- Answer is human-readable and stable\n- Based on completed work (won't change)\n\n**Example 3: Complex aggregation requiring multiple steps (Issue Tracker MCP)**\n```xml\n<qa_pair>\n   <question>Among all bugs reported in January 2024 that were marked as critical priority, which assignee resolved the highest percentage of their assigned bugs within 48 hours? Provide the assignee's username.</question>\n   <answer>alex_eng</answer>\n</qa_pair>\n```\n\nThis question is good because:\n- Requires filtering bugs by date, priority, and status\n- Needs to group by assignee and calculate resolution rates\n- Requires understanding timestamps to determine 48-hour windows\n- Tests pagination (potentially many bugs to process)\n- Answer is a single username\n- Based on historical data from specific time period\n\n**Example 4: Requires synthesis across multiple data types (CRM MCP)**\n```xml\n<qa_pair>\n   <question>Find the account that upgraded from the Starter to Enterprise plan in Q4 2023 and had the highest annual contract value. What industry does this account operate in?</question>\n   <answer>Healthcare</answer>\n</qa_pair>\n```\n\nThis question is good because:\n- Requires understanding subscription tier changes\n- Needs to identify upgrade events in specific timeframe\n- Requires comparing contract values\n- Must access account industry information\n- Answer is simple and verifiable\n- Based on completed historical transactions\n\n### Poor Questions\n\n**Example 1: Answer changes over time**\n```xml\n<qa_pair>\n   <question>How many open issues are currently assigned to the engineering team?</question>\n   <answer>47</answer>\n</qa_pair>\n```\n\nThis question is poor because:\n- The answer will change as issues are created, closed, or reassigned\n- Not based on stable/stationary data\n- Relies on \"current state\" which is dynamic\n\n**Example 2: Too easy with keyword search**\n```xml\n<qa_pair>\n   <question>Find the pull request with title \"Add authentication feature\" and tell me who created it.</question>\n   <answer>developer123</answer>\n</qa_pair>\n```\n\nThis question is poor because:\n- Can be solved with a straightforward keyword search for exact title\n- Doesn't require deep exploration or understanding\n- No synthesis or analysis needed\n\n**Example 3: Ambiguous answer format**\n```xml\n<qa_pair>\n   <question>List all the repositories that have Python as their primary language.</question>\n   <answer>repo1, repo2, repo3, data-pipeline, ml-tools</answer>\n</qa_pair>\n```\n\nThis question is poor because:\n- Answer is a list that could be returned in any order\n- Difficult to verify with direct string comparison\n- LLM might format differently (JSON array, comma-separated, newline-separated)\n- Better to ask for a specific aggregate (count) or superlative (most stars)\n\n## Verification Process\n\nAfter creating evaluations:\n\n1. **Examine the XML file** to understand the schema\n2. **Load each task instruction** and in parallel using the MCP server and tools, identify the correct answer by attempting to solve the task YOURSELF\n3. **Flag any operations** that require WRITE or DESTRUCTIVE operations\n4. **Accumulate all CORRECT answers** and replace any incorrect answers in the document\n5. **Remove any `<qa_pair>`** that require WRITE or DESTRUCTIVE operations\n\nRemember to parallelize solving tasks to avoid running out of context, then accumulate all answers and make changes to the file at the end.\n\n## Tips for Creating Quality Evaluations\n\n1. **Think Hard and Plan Ahead** before generating tasks\n2. **Parallelize Where Opportunity Arises** to speed up the process and manage context\n3. **Focus on Realistic Use Cases** that humans would actually want to accomplish\n4. **Create Challenging Questions** that test the limits of the MCP server's capabilities\n5. **Ensure Stability** by using historical data and closed concepts\n6. **Verify Answers** by solving the questions yourself using the MCP server tools\n7. **Iterate and Refine** based on what you learn during the process\n\n---\n\n# Running Evaluations\n\nAfter creating your evaluation file, you can use the provided evaluation harness to test your MCP server.\n\n## Setup\n\n1. **Install Dependencies**\n\n   ```bash\n   pip install -r scripts/requirements.txt\n   ```\n\n   Or install manually:\n   ```bash\n   pip install anthropic mcp\n   ```\n\n2. **Set API Key**\n\n   ```bash\n   export ANTHROPIC_API_KEY=your_api_key_here\n   ```\n\n## Evaluation File Format\n\nEvaluation files use XML format with `<qa_pair>` elements:\n\n```xml\n<evaluation>\n   <qa_pair>\n      <question>Find the project created in Q2 2024 with the highest number of completed tasks. What is the project name?</question>\n      <answer>Website Redesign</answer>\n   </qa_pair>\n   <qa_pair>\n      <question>Search for issues labeled as \"bug\" that were closed in March 2024. Which user closed the most issues? Provide their username.</question>\n      <answer>sarah_dev</answer>\n   </qa_pair>\n</evaluation>\n```\n\n## Running Evaluations\n\nThe evaluation script (`scripts/evaluation.py`) supports three transport types:\n\n**Important:**\n- **stdio transport**: The evaluation script automatically launches and manages the MCP server process for you. Do not run the server manually.\n- **sse/http transports**: You must start the MCP server separately before running the evaluation. The script connects to the already-running server at the specified URL.\n\n### 1. Local STDIO Server\n\nFor locally-run MCP servers (script launches the server automatically):\n\n```bash\npython scripts/evaluation.py \\\n  -t stdio \\\n  -c python \\\n  -a my_mcp_server.py \\\n  evaluation.xml\n```\n\nWith environment variables:\n```bash\npython scripts/evaluation.py \\\n  -t stdio \\\n  -c python \\\n  -a my_mcp_server.py \\\n  -e API_KEY=abc123 \\\n  -e DEBUG=true \\\n  evaluation.xml\n```\n\n### 2. Server-Sent Events (SSE)\n\nFor SSE-based MCP servers (you must start the server first):\n\n```bash\npython scripts/evaluation.py \\\n  -t sse \\\n  -u https://example.com/mcp \\\n  -H \"Authorization: Bearer token123\" \\\n  -H \"X-Custom-Header: value\" \\\n  evaluation.xml\n```\n\n### 3. HTTP (Streamable HTTP)\n\nFor HTTP-based MCP servers (you must start the server first):\n\n```bash\npython scripts/evaluation.py \\\n  -t http \\\n  -u https://example.com/mcp \\\n  -H \"Authorization: Bearer token123\" \\\n  evaluation.xml\n```\n\n## Command-Line Options\n\n```\nusage: evaluation.py [-h] [-t {stdio,sse,http}] [-m MODEL] [-c COMMAND]\n                     [-a ARGS [ARGS ...]] [-e ENV [ENV ...]] [-u URL]\n                     [-H HEADERS [HEADERS ...]] [-o OUTPUT]\n                     eval_file\n\npositional arguments:\n  eval_file             Path to evaluation XML file\n\noptional arguments:\n  -h, --help            Show help message\n  -t, --transport       Transport type: stdio, sse, or http (default: stdio)\n  -m, --model           Claude model to use (default: claude-3-7-sonnet-20250219)\n  -o, --output          Output file for report (default: print to stdout)\n\nstdio options:\n  -c, --command         Command to run MCP server (e.g., python, node)\n  -a, --args            Arguments for the command (e.g., server.py)\n  -e, --env             Environment variables in KEY=VALUE format\n\nsse/http options:\n  -u, --url             MCP server URL\n  -H, --header          HTTP headers in 'Key: Value' format\n```\n\n## Output\n\nThe evaluation script generates a detailed report including:\n\n- **Summary Statistics**:\n  - Accuracy (correct/total)\n  - Average task duration\n  - Average tool calls per task\n  - Total tool calls\n\n- **Per-Task Results**:\n  - Prompt and expected response\n  - Actual response from the agent\n  - Whether the answer was correct (✅/❌)\n  - Duration and tool call details\n  - Agent's summary of its approach\n  - Agent's feedback on the tools\n\n### Save Report to File\n\n```bash\npython scripts/evaluation.py \\\n  -t stdio \\\n  -c python \\\n  -a my_server.py \\\n  -o evaluation_report.md \\\n  evaluation.xml\n```\n\n## Complete Example Workflow\n\nHere's a complete example of creating and running an evaluation:\n\n1. **Create your evaluation file** (`my_evaluation.xml`):\n\n```xml\n<evaluation>\n   <qa_pair>\n      <question>Find the user who created the most issues in January 2024. What is their username?</question>\n      <answer>alice_developer</answer>\n   </qa_pair>\n   <qa_pair>\n      <question>Among all pull requests merged in Q1 2024, which repository had the highest number? Provide the repository name.</question>\n      <answer>backend-api</answer>\n   </qa_pair>\n   <qa_pair>\n      <question>Find the project that was completed in December 2023 and had the longest duration from start to finish. How many days did it take?</question>\n      <answer>127</answer>\n   </qa_pair>\n</evaluation>\n```\n\n2. **Install dependencies**:\n\n```bash\npip install -r scripts/requirements.txt\nexport ANTHROPIC_API_KEY=your_api_key\n```\n\n3. **Run evaluation**:\n\n```bash\npython scripts/evaluation.py \\\n  -t stdio \\\n  -c python \\\n  -a github_mcp_server.py \\\n  -e GITHUB_TOKEN=ghp_xxx \\\n  -o github_eval_report.md \\\n  my_evaluation.xml\n```\n\n4. **Review the report** in `github_eval_report.md` to:\n   - See which questions passed/failed\n   - Read the agent's feedback on your tools\n   - Identify areas for improvement\n   - Iterate on your MCP server design\n\n## Troubleshooting\n\n### Connection Errors\n\nIf you get connection errors:\n- **STDIO**: Verify the command and arguments are correct\n- **SSE/HTTP**: Check the URL is accessible and headers are correct\n- Ensure any required API keys are set in environment variables or headers\n\n### Low Accuracy\n\nIf many evaluations fail:\n- Review the agent's feedback for each task\n- Check if tool descriptions are clear and comprehensive\n- Verify input parameters are well-documented\n- Consider whether tools return too much or too little data\n- Ensure error messages are actionable\n\n### Timeout Issues\n\nIf tasks are timing out:\n- Use a more capable model (e.g., `claude-3-7-sonnet-20250219`)\n- Check if tools are returning too much data\n- Verify pagination is working correctly\n- Consider simplifying complex questions\n","core/skills/builtin/mcp-builder/reference/mcp_best_practices.md":"# MCP Server Best Practices\n\n## Quick Reference\n\n### Server Naming\n- **Python**: `{service}_mcp` (e.g., `slack_mcp`)\n- **Node/TypeScript**: `{service}-mcp-server` (e.g., `slack-mcp-server`)\n\n### Tool Naming\n- Use snake_case with service prefix\n- Format: `{service}_{action}_{resource}`\n- Example: `slack_send_message`, `github_create_issue`\n\n### Response Formats\n- Support both JSON and Markdown formats\n- JSON for programmatic processing\n- Markdown for human readability\n\n### Pagination\n- Always respect `limit` parameter\n- Return `has_more`, `next_offset`, `total_count`\n- Default to 20-50 items\n\n### Transport\n- **Streamable HTTP**: For remote servers, multi-client scenarios\n- **stdio**: For local integrations, command-line tools\n- Avoid SSE (deprecated in favor of streamable HTTP)\n\n---\n\n## Server Naming Conventions\n\nFollow these standardized naming patterns:\n\n**Python**: Use format `{service}_mcp` (lowercase with underscores)\n- Examples: `slack_mcp`, `github_mcp`, `jira_mcp`\n\n**Node/TypeScript**: Use format `{service}-mcp-server` (lowercase with hyphens)\n- Examples: `slack-mcp-server`, `github-mcp-server`, `jira-mcp-server`\n\nThe name should be general, descriptive of the service being integrated, easy to infer from the task description, and without version numbers.\n\n---\n\n## Tool Naming and Design\n\n### Tool Naming\n\n1. **Use snake_case**: `search_users`, `create_project`, `get_channel_info`\n2. **Include service prefix**: Anticipate that your MCP server may be used alongside other MCP servers\n   - Use `slack_send_message` instead of just `send_message`\n   - Use `github_create_issue` instead of just `create_issue`\n3. **Be action-oriented**: Start with verbs (get, list, search, create, etc.)\n4. **Be specific**: Avoid generic names that could conflict with other servers\n\n### Tool Design\n\n- Tool descriptions must narrowly and unambiguously describe functionality\n- Descriptions must precisely match actual functionality\n- Provide tool annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint)\n- Keep tool operations focused and atomic\n\n---\n\n## Response Formats\n\nAll tools that return data should support multiple formats:\n\n### JSON Format (`response_format=\"json\"`)\n- Machine-readable structured data\n- Include all available fields and metadata\n- Consistent field names and types\n- Use for programmatic processing\n\n### Markdown Format (`response_format=\"markdown\"`, typically default)\n- Human-readable formatted text\n- Use headers, lists, and formatting for clarity\n- Convert timestamps to human-readable format\n- Show display names with IDs in parentheses\n- Omit verbose metadata\n\n---\n\n## Pagination\n\nFor tools that list resources:\n\n- **Always respect the `limit` parameter**\n- **Implement pagination**: Use `offset` or cursor-based pagination\n- **Return pagination metadata**: Include `has_more`, `next_offset`/`next_cursor`, `total_count`\n- **Never load all results into memory**: Especially important for large datasets\n- **Default to reasonable limits**: 20-50 items is typical\n\nExample pagination response:\n```json\n{\n  \"total\": 150,\n  \"count\": 20,\n  \"offset\": 0,\n  \"items\": [...],\n  \"has_more\": true,\n  \"next_offset\": 20\n}\n```\n\n---\n\n## Transport Options\n\n### Streamable HTTP\n\n**Best for**: Remote servers, web services, multi-client scenarios\n\n**Characteristics**:\n- Bidirectional communication over HTTP\n- Supports multiple simultaneous clients\n- Can be deployed as a web service\n- Enables server-to-client notifications\n\n**Use when**:\n- Serving multiple clients simultaneously\n- Deploying as a cloud service\n- Integration with web applications\n\n### stdio\n\n**Best for**: Local integrations, command-line tools\n\n**Characteristics**:\n- Standard input/output stream communication\n- Simple setup, no network configuration needed\n- Runs as a subprocess of the client\n\n**Use when**:\n- Building tools for local development environments\n- Integrating with desktop applications\n- Single-user, single-session scenarios\n\n**Note**: stdio servers should NOT log to stdout (use stderr for logging)\n\n### Transport Selection\n\n| Criterion | stdio | Streamable HTTP |\n|-----------|-------|-----------------|\n| **Deployment** | Local | Remote |\n| **Clients** | Single | Multiple |\n| **Complexity** | Low | Medium |\n| **Real-time** | No | Yes |\n\n---\n\n## Security Best Practices\n\n### Authentication and Authorization\n\n**OAuth 2.1**:\n- Use secure OAuth 2.1 with certificates from recognized authorities\n- Validate access tokens before processing requests\n- Only accept tokens specifically intended for your server\n\n**API Keys**:\n- Store API keys in environment variables, never in code\n- Validate keys on server startup\n- Provide clear error messages when authentication fails\n\n### Input Validation\n\n- Sanitize file paths to prevent directory traversal\n- Validate URLs and external identifiers\n- Check parameter sizes and ranges\n- Prevent command injection in system calls\n- Use schema validation (Pydantic/Zod) for all inputs\n\n### Error Handling\n\n- Don't expose internal errors to clients\n- Log security-relevant errors server-side\n- Provide helpful but not revealing error messages\n- Clean up resources after errors\n\n### DNS Rebinding Protection\n\nFor streamable HTTP servers running locally:\n- Enable DNS rebinding protection\n- Validate the `Origin` header on all incoming connections\n- Bind to `127.0.0.1` rather than `0.0.0.0`\n\n---\n\n## Tool Annotations\n\nProvide annotations to help clients understand tool behavior:\n\n| Annotation | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `readOnlyHint` | boolean | false | Tool does not modify its environment |\n| `destructiveHint` | boolean | true | Tool may perform destructive updates |\n| `idempotentHint` | boolean | false | Repeated calls with same args have no additional effect |\n| `openWorldHint` | boolean | true | Tool interacts with external entities |\n\n**Important**: Annotations are hints, not security guarantees. Clients should not make security-critical decisions based solely on annotations.\n\n---\n\n## Error Handling\n\n- Use standard JSON-RPC error codes\n- Report tool errors within result objects (not protocol-level errors)\n- Provide helpful, specific error messages with suggested next steps\n- Don't expose internal implementation details\n- Clean up resources properly on errors\n\nExample error handling:\n```typescript\ntry {\n  const result = performOperation();\n  return { content: [{ type: \"text\", text: result }] };\n} catch (error) {\n  return {\n    isError: true,\n    content: [{\n      type: \"text\",\n      text: `Error: ${error.message}. Try using filter='active_only' to reduce results.`\n    }]\n  };\n}\n```\n\n---\n\n## Testing Requirements\n\nComprehensive testing should cover:\n\n- **Functional testing**: Verify correct execution with valid/invalid inputs\n- **Integration testing**: Test interaction with external systems\n- **Security testing**: Validate auth, input sanitization, rate limiting\n- **Performance testing**: Check behavior under load, timeouts\n- **Error handling**: Ensure proper error reporting and cleanup\n\n---\n\n## Documentation Requirements\n\n- Provide clear documentation of all tools and capabilities\n- Include working examples (at least 3 per major feature)\n- Document security considerations\n- Specify required permissions and access levels\n- Document rate limits and performance characteristics\n","core/skills/builtin/mcp-builder/reference/node_mcp_server.md":"# Node/TypeScript MCP Server Implementation Guide\n\n## Overview\n\nThis document provides Node/TypeScript-specific best practices and examples for implementing MCP servers using the MCP TypeScript SDK. It covers project structure, server setup, tool registration patterns, input validation with Zod, error handling, and complete working examples.\n\n---\n\n## Quick Reference\n\n### Key Imports\n```typescript\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport express from \"express\";\nimport { z } from \"zod\";\n```\n\n### Server Initialization\n```typescript\nconst server = new McpServer({\n  name: \"service-mcp-server\",\n  version: \"1.0.0\"\n});\n```\n\n### Tool Registration Pattern\n```typescript\nserver.registerTool(\n  \"tool_name\",\n  {\n    title: \"Tool Display Name\",\n    description: \"What the tool does\",\n    inputSchema: { param: z.string() },\n    outputSchema: { result: z.string() }\n  },\n  async ({ param }) => {\n    const output = { result: `Processed: ${param}` };\n    return {\n      content: [{ type: \"text\", text: JSON.stringify(output) }],\n      structuredContent: output // Modern pattern for structured data\n    };\n  }\n);\n```\n\n---\n\n## MCP TypeScript SDK\n\nThe official MCP TypeScript SDK provides:\n- `McpServer` class for server initialization\n- `registerTool` method for tool registration\n- Zod schema integration for runtime input validation\n- Type-safe tool handler implementations\n\n**IMPORTANT - Use Modern APIs Only:**\n- **DO use**: `server.registerTool()`, `server.registerResource()`, `server.registerPrompt()`\n- **DO NOT use**: Old deprecated APIs such as `server.tool()`, `server.setRequestHandler(ListToolsRequestSchema, ...)`, or manual handler registration\n- The `register*` methods provide better type safety, automatic schema handling, and are the recommended approach\n\nSee the MCP SDK documentation in the references for complete details.\n\n## Server Naming Convention\n\nNode/TypeScript MCP servers must follow this naming pattern:\n- **Format**: `{service}-mcp-server` (lowercase with hyphens)\n- **Examples**: `github-mcp-server`, `jira-mcp-server`, `stripe-mcp-server`\n\nThe name should be:\n- General (not tied to specific features)\n- Descriptive of the service/API being integrated\n- Easy to infer from the task description\n- Without version numbers or dates\n\n## Project Structure\n\nCreate the following structure for Node/TypeScript MCP servers:\n\n```\n{service}-mcp-server/\n├── package.json\n├── tsconfig.json\n├── README.md\n├── src/\n│   ├── index.ts          # Main entry point with McpServer initialization\n│   ├── types.ts          # TypeScript type definitions and interfaces\n│   ├── tools/            # Tool implementations (one file per domain)\n│   ├── services/         # API clients and shared utilities\n│   ├── schemas/          # Zod validation schemas\n│   └── constants.ts      # Shared constants (API_URL, CHARACTER_LIMIT, etc.)\n└── dist/                 # Built JavaScript files (entry point: dist/index.js)\n```\n\n## Tool Implementation\n\n### Tool Naming\n\nUse snake_case for tool names (e.g., \"search_users\", \"create_project\", \"get_channel_info\") with clear, action-oriented names.\n\n**Avoid Naming Conflicts**: Include the service context to prevent overlaps:\n- Use \"slack_send_message\" instead of just \"send_message\"\n- Use \"github_create_issue\" instead of just \"create_issue\"\n- Use \"asana_list_tasks\" instead of just \"list_tasks\"\n\n### Tool Structure\n\nTools are registered using the `registerTool` method with the following requirements:\n- Use Zod schemas for runtime input validation and type safety\n- The `description` field must be explicitly provided - JSDoc comments are NOT automatically extracted\n- Explicitly provide `title`, `description`, `inputSchema`, and `annotations`\n- The `inputSchema` must be a Zod schema object (not a JSON schema)\n- Type all parameters and return values explicitly\n\n```typescript\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\n\nconst server = new McpServer({\n  name: \"example-mcp\",\n  version: \"1.0.0\"\n});\n\n// Zod schema for input validation\nconst UserSearchInputSchema = z.object({\n  query: z.string()\n    .min(2, \"Query must be at least 2 characters\")\n    .max(200, \"Query must not exceed 200 characters\")\n    .describe(\"Search string to match against names/emails\"),\n  limit: z.number()\n    .int()\n    .min(1)\n    .max(100)\n    .default(20)\n    .describe(\"Maximum results to return\"),\n  offset: z.number()\n    .int()\n    .min(0)\n    .default(0)\n    .describe(\"Number of results to skip for pagination\"),\n  response_format: z.nativeEnum(ResponseFormat)\n    .default(ResponseFormat.MARKDOWN)\n    .describe(\"Output format: 'markdown' for human-readable or 'json' for machine-readable\")\n}).strict();\n\n// Type definition from Zod schema\ntype UserSearchInput = z.infer<typeof UserSearchInputSchema>;\n\nserver.registerTool(\n  \"example_search_users\",\n  {\n    title: \"Search Example Users\",\n    description: `Search for users in the Example system by name, email, or team.\n\nThis tool searches across all user profiles in the Example platform, supporting partial matches and various search filters. It does NOT create or modify users, only searches existing ones.\n\nArgs:\n  - query (string): Search string to match against names/emails\n  - limit (number): Maximum results to return, between 1-100 (default: 20)\n  - offset (number): Number of results to skip for pagination (default: 0)\n  - response_format ('markdown' | 'json'): Output format (default: 'markdown')\n\nReturns:\n  For JSON format: Structured data with schema:\n  {\n    \"total\": number,           // Total number of matches found\n    \"count\": number,           // Number of results in this response\n    \"offset\": number,          // Current pagination offset\n    \"users\": [\n      {\n        \"id\": string,          // User ID (e.g., \"U123456789\")\n        \"name\": string,        // Full name (e.g., \"John Doe\")\n        \"email\": string,       // Email address\n        \"team\": string,        // Team name (optional)\n        \"active\": boolean      // Whether user is active\n      }\n    ],\n    \"has_more\": boolean,       // Whether more results are available\n    \"next_offset\": number      // Offset for next page (if has_more is true)\n  }\n\nExamples:\n  - Use when: \"Find all marketing team members\" -> params with query=\"team:marketing\"\n  - Use when: \"Search for John's account\" -> params with query=\"john\"\n  - Don't use when: You need to create a user (use example_create_user instead)\n\nError Handling:\n  - Returns \"Error: Rate limit exceeded\" if too many requests (429 status)\n  - Returns \"No users found matching '<query>'\" if search returns empty`,\n    inputSchema: UserSearchInputSchema,\n    annotations: {\n      readOnlyHint: true,\n      destructiveHint: false,\n      idempotentHint: true,\n      openWorldHint: true\n    }\n  },\n  async (params: UserSearchInput) => {\n    try {\n      // Input validation is handled by Zod schema\n      // Make API request using validated parameters\n      const data = await makeApiRequest<any>(\n        \"users/search\",\n        \"GET\",\n        undefined,\n        {\n          q: params.query,\n          limit: params.limit,\n          offset: params.offset\n        }\n      );\n\n      const users = data.users || [];\n      const total = data.total || 0;\n\n      if (!users.length) {\n        return {\n          content: [{\n            type: \"text\",\n            text: `No users found matching '${params.query}'`\n          }]\n        };\n      }\n\n      // Prepare structured output\n      const output = {\n        total,\n        count: users.length,\n        offset: params.offset,\n        users: users.map((user: any) => ({\n          id: user.id,\n          name: user.name,\n          email: user.email,\n          ...(user.team ? { team: user.team } : {}),\n          active: user.active ?? true\n        })),\n        has_more: total > params.offset + users.length,\n        ...(total > params.offset + users.length ? {\n          next_offset: params.offset + users.length\n        } : {})\n      };\n\n      // Format text representation based on requested format\n      let textContent: string;\n      if (params.response_format === ResponseFormat.MARKDOWN) {\n        const lines = [`# User Search Results: '${params.query}'`, \"\",\n          `Found ${total} users (showing ${users.length})`, \"\"];\n        for (const user of users) {\n          lines.push(`## ${user.name} (${user.id})`);\n          lines.push(`- **Email**: ${user.email}`);\n          if (user.team) lines.push(`- **Team**: ${user.team}`);\n          lines.push(\"\");\n        }\n        textContent = lines.join(\"\\n\");\n      } else {\n        textContent = JSON.stringify(output, null, 2);\n      }\n\n      return {\n        content: [{ type: \"text\", text: textContent }],\n        structuredContent: output // Modern pattern for structured data\n      };\n    } catch (error) {\n      return {\n        content: [{\n          type: \"text\",\n          text: handleApiError(error)\n        }]\n      };\n    }\n  }\n);\n```\n\n## Zod Schemas for Input Validation\n\nZod provides runtime type validation:\n\n```typescript\nimport { z } from \"zod\";\n\n// Basic schema with validation\nconst CreateUserSchema = z.object({\n  name: z.string()\n    .min(1, \"Name is required\")\n    .max(100, \"Name must not exceed 100 characters\"),\n  email: z.string()\n    .email(\"Invalid email format\"),\n  age: z.number()\n    .int(\"Age must be a whole number\")\n    .min(0, \"Age cannot be negative\")\n    .max(150, \"Age cannot be greater than 150\")\n}).strict();  // Use .strict() to forbid extra fields\n\n// Enums\nenum ResponseFormat {\n  MARKDOWN = \"markdown\",\n  JSON = \"json\"\n}\n\nconst SearchSchema = z.object({\n  response_format: z.nativeEnum(ResponseFormat)\n    .default(ResponseFormat.MARKDOWN)\n    .describe(\"Output format\")\n});\n\n// Optional fields with defaults\nconst PaginationSchema = z.object({\n  limit: z.number()\n    .int()\n    .min(1)\n    .max(100)\n    .default(20)\n    .describe(\"Maximum results to return\"),\n  offset: z.number()\n    .int()\n    .min(0)\n    .default(0)\n    .describe(\"Number of results to skip\")\n});\n```\n\n## Response Format Options\n\nSupport multiple output formats for flexibility:\n\n```typescript\nenum ResponseFormat {\n  MARKDOWN = \"markdown\",\n  JSON = \"json\"\n}\n\nconst inputSchema = z.object({\n  query: z.string(),\n  response_format: z.nativeEnum(ResponseFormat)\n    .default(ResponseFormat.MARKDOWN)\n    .describe(\"Output format: 'markdown' for human-readable or 'json' for machine-readable\")\n});\n```\n\n**Markdown format**:\n- Use headers, lists, and formatting for clarity\n- Convert timestamps to human-readable format\n- Show display names with IDs in parentheses\n- Omit verbose metadata\n- Group related information logically\n\n**JSON format**:\n- Return complete, structured data suitable for programmatic processing\n- Include all available fields and metadata\n- Use consistent field names and types\n\n## Pagination Implementation\n\nFor tools that list resources:\n\n```typescript\nconst ListSchema = z.object({\n  limit: z.number().int().min(1).max(100).default(20),\n  offset: z.number().int().min(0).default(0)\n});\n\nasync function listItems(params: z.infer<typeof ListSchema>) {\n  const data = await apiRequest(params.limit, params.offset);\n\n  const response = {\n    total: data.total,\n    count: data.items.length,\n    offset: params.offset,\n    items: data.items,\n    has_more: data.total > params.offset + data.items.length,\n    next_offset: data.total > params.offset + data.items.length\n      ? params.offset + data.items.length\n      : undefined\n  };\n\n  return JSON.stringify(response, null, 2);\n}\n```\n\n## Character Limits and Truncation\n\nAdd a CHARACTER_LIMIT constant to prevent overwhelming responses:\n\n```typescript\n// At module level in constants.ts\nexport const CHARACTER_LIMIT = 25000;  // Maximum response size in characters\n\nasync function searchTool(params: SearchInput) {\n  let result = generateResponse(data);\n\n  // Check character limit and truncate if needed\n  if (result.length > CHARACTER_LIMIT) {\n    const truncatedData = data.slice(0, Math.max(1, data.length / 2));\n    response.data = truncatedData;\n    response.truncated = true;\n    response.truncation_message =\n      `Response truncated from ${data.length} to ${truncatedData.length} items. ` +\n      `Use 'offset' parameter or add filters to see more results.`;\n    result = JSON.stringify(response, null, 2);\n  }\n\n  return result;\n}\n```\n\n## Error Handling\n\nProvide clear, actionable error messages:\n\n```typescript\nimport axios, { AxiosError } from \"axios\";\n\nfunction handleApiError(error: unknown): string {\n  if (error instanceof AxiosError) {\n    if (error.response) {\n      switch (error.response.status) {\n        case 404:\n          return \"Error: Resource not found. Please check the ID is correct.\";\n        case 403:\n          return \"Error: Permission denied. You don't have access to this resource.\";\n        case 429:\n          return \"Error: Rate limit exceeded. Please wait before making more requests.\";\n        default:\n          return `Error: API request failed with status ${error.response.status}`;\n      }\n    } else if (error.code === \"ECONNABORTED\") {\n      return \"Error: Request timed out. Please try again.\";\n    }\n  }\n  return `Error: Unexpected error occurred: ${error instanceof Error ? error.message : String(error)}`;\n}\n```\n\n## Shared Utilities\n\nExtract common functionality into reusable functions:\n\n```typescript\n// Shared API request function\nasync function makeApiRequest<T>(\n  endpoint: string,\n  method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" = \"GET\",\n  data?: any,\n  params?: any\n): Promise<T> {\n  try {\n    const response = await axios({\n      method,\n      url: `${API_BASE_URL}/${endpoint}`,\n      data,\n      params,\n      timeout: 30000,\n      headers: {\n        \"Content-Type\": \"application/json\",\n        \"Accept\": \"application/json\"\n      }\n    });\n    return response.data;\n  } catch (error) {\n    throw error;\n  }\n}\n```\n\n## Async/Await Best Practices\n\nAlways use async/await for network requests and I/O operations:\n\n```typescript\n// Good: Async network request\nasync function fetchData(resourceId: string): Promise<ResourceData> {\n  const response = await axios.get(`${API_URL}/resource/${resourceId}`);\n  return response.data;\n}\n\n// Bad: Promise chains\nfunction fetchData(resourceId: string): Promise<ResourceData> {\n  return axios.get(`${API_URL}/resource/${resourceId}`)\n    .then(response => response.data);  // Harder to read and maintain\n}\n```\n\n## TypeScript Best Practices\n\n1. **Use Strict TypeScript**: Enable strict mode in tsconfig.json\n2. **Define Interfaces**: Create clear interface definitions for all data structures\n3. **Avoid `any`**: Use proper types or `unknown` instead of `any`\n4. **Zod for Runtime Validation**: Use Zod schemas to validate external data\n5. **Type Guards**: Create type guard functions for complex type checking\n6. **Error Handling**: Always use try-catch with proper error type checking\n7. **Null Safety**: Use optional chaining (`?.`) and nullish coalescing (`??`)\n\n```typescript\n// Good: Type-safe with Zod and interfaces\ninterface UserResponse {\n  id: string;\n  name: string;\n  email: string;\n  team?: string;\n  active: boolean;\n}\n\nconst UserSchema = z.object({\n  id: z.string(),\n  name: z.string(),\n  email: z.string().email(),\n  team: z.string().optional(),\n  active: z.boolean()\n});\n\ntype User = z.infer<typeof UserSchema>;\n\nasync function getUser(id: string): Promise<User> {\n  const data = await apiCall(`/users/${id}`);\n  return UserSchema.parse(data);  // Runtime validation\n}\n\n// Bad: Using any\nasync function getUser(id: string): Promise<any> {\n  return await apiCall(`/users/${id}`);  // No type safety\n}\n```\n\n## Package Configuration\n\n### package.json\n\n```json\n{\n  \"name\": \"{service}-mcp-server\",\n  \"version\": \"1.0.0\",\n  \"description\": \"MCP server for {Service} API integration\",\n  \"type\": \"module\",\n  \"main\": \"dist/index.js\",\n  \"scripts\": {\n    \"start\": \"node dist/index.js\",\n    \"dev\": \"tsx watch src/index.ts\",\n    \"build\": \"tsc\",\n    \"clean\": \"rm -rf dist\"\n  },\n  \"engines\": {\n    \"node\": \">=18\"\n  },\n  \"dependencies\": {\n    \"@modelcontextprotocol/sdk\": \"^1.6.1\",\n    \"axios\": \"^1.7.9\",\n    \"zod\": \"^3.23.8\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.10.0\",\n    \"tsx\": \"^4.19.2\",\n    \"typescript\": \"^5.7.2\"\n  }\n}\n```\n\n### tsconfig.json\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"Node16\",\n    \"moduleResolution\": \"Node16\",\n    \"lib\": [\"ES2022\"],\n    \"outDir\": \"./dist\",\n    \"rootDir\": \"./src\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"declaration\": true,\n    \"declarationMap\": true,\n    \"sourceMap\": true,\n    \"allowSyntheticDefaultImports\": true\n  },\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"node_modules\", \"dist\"]\n}\n```\n\n## Complete Example\n\n```typescript\n#!/usr/bin/env node\n/**\n * MCP Server for Example Service.\n *\n * This server provides tools to interact with Example API, including user search,\n * project management, and data export capabilities.\n */\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport axios, { AxiosError } from \"axios\";\n\n// Constants\nconst API_BASE_URL = \"https://api.example.com/v1\";\nconst CHARACTER_LIMIT = 25000;\n\n// Enums\nenum ResponseFormat {\n  MARKDOWN = \"markdown\",\n  JSON = \"json\"\n}\n\n// Zod schemas\nconst UserSearchInputSchema = z.object({\n  query: z.string()\n    .min(2, \"Query must be at least 2 characters\")\n    .max(200, \"Query must not exceed 200 characters\")\n    .describe(\"Search string to match against names/emails\"),\n  limit: z.number()\n    .int()\n    .min(1)\n    .max(100)\n    .default(20)\n    .describe(\"Maximum results to return\"),\n  offset: z.number()\n    .int()\n    .min(0)\n    .default(0)\n    .describe(\"Number of results to skip for pagination\"),\n  response_format: z.nativeEnum(ResponseFormat)\n    .default(ResponseFormat.MARKDOWN)\n    .describe(\"Output format: 'markdown' for human-readable or 'json' for machine-readable\")\n}).strict();\n\ntype UserSearchInput = z.infer<typeof UserSearchInputSchema>;\n\n// Shared utility functions\nasync function makeApiRequest<T>(\n  endpoint: string,\n  method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" = \"GET\",\n  data?: any,\n  params?: any\n): Promise<T> {\n  try {\n    const response = await axios({\n      method,\n      url: `${API_BASE_URL}/${endpoint}`,\n      data,\n      params,\n      timeout: 30000,\n      headers: {\n        \"Content-Type\": \"application/json\",\n        \"Accept\": \"application/json\"\n      }\n    });\n    return response.data;\n  } catch (error) {\n    throw error;\n  }\n}\n\nfunction handleApiError(error: unknown): string {\n  if (error instanceof AxiosError) {\n    if (error.response) {\n      switch (error.response.status) {\n        case 404:\n          return \"Error: Resource not found. Please check the ID is correct.\";\n        case 403:\n          return \"Error: Permission denied. You don't have access to this resource.\";\n        case 429:\n          return \"Error: Rate limit exceeded. Please wait before making more requests.\";\n        default:\n          return `Error: API request failed with status ${error.response.status}`;\n      }\n    } else if (error.code === \"ECONNABORTED\") {\n      return \"Error: Request timed out. Please try again.\";\n    }\n  }\n  return `Error: Unexpected error occurred: ${error instanceof Error ? error.message : String(error)}`;\n}\n\n// Create MCP server instance\nconst server = new McpServer({\n  name: \"example-mcp\",\n  version: \"1.0.0\"\n});\n\n// Register tools\nserver.registerTool(\n  \"example_search_users\",\n  {\n    title: \"Search Example Users\",\n    description: `[Full description as shown above]`,\n    inputSchema: UserSearchInputSchema,\n    annotations: {\n      readOnlyHint: true,\n      destructiveHint: false,\n      idempotentHint: true,\n      openWorldHint: true\n    }\n  },\n  async (params: UserSearchInput) => {\n    // Implementation as shown above\n  }\n);\n\n// Main function\n// For stdio (local):\nasync function runStdio() {\n  if (!process.env.EXAMPLE_API_KEY) {\n    console.error(\"ERROR: EXAMPLE_API_KEY environment variable is required\");\n    process.exit(1);\n  }\n\n  const transport = new StdioServerTransport();\n  await server.connect(transport);\n  console.error(\"MCP server running via stdio\");\n}\n\n// For streamable HTTP (remote):\nasync function runHTTP() {\n  if (!process.env.EXAMPLE_API_KEY) {\n    console.error(\"ERROR: EXAMPLE_API_KEY environment variable is required\");\n    process.exit(1);\n  }\n\n  const app = express();\n  app.use(express.json());\n\n  app.post('/mcp', async (req, res) => {\n    const transport = new StreamableHTTPServerTransport({\n      sessionIdGenerator: undefined,\n      enableJsonResponse: true\n    });\n    res.on('close', () => transport.close());\n    await server.connect(transport);\n    await transport.handleRequest(req, res, req.body);\n  });\n\n  const port = parseInt(process.env.PORT || '3000');\n  app.listen(port, () => {\n    console.error(`MCP server running on http://localhost:${port}/mcp`);\n  });\n}\n\n// Choose transport based on environment\nconst transport = process.env.TRANSPORT || 'stdio';\nif (transport === 'http') {\n  runHTTP().catch(error => {\n    console.error(\"Server error:\", error);\n    process.exit(1);\n  });\n} else {\n  runStdio().catch(error => {\n    console.error(\"Server error:\", error);\n    process.exit(1);\n  });\n}\n```\n\n---\n\n## Advanced MCP Features\n\n### Resource Registration\n\nExpose data as resources for efficient, URI-based access:\n\n```typescript\nimport { ResourceTemplate } from \"@modelcontextprotocol/sdk/types.js\";\n\n// Register a resource with URI template\nserver.registerResource(\n  {\n    uri: \"file://documents/{name}\",\n    name: \"Document Resource\",\n    description: \"Access documents by name\",\n    mimeType: \"text/plain\"\n  },\n  async (uri: string) => {\n    // Extract parameter from URI\n    const match = uri.match(/^file:\\/\\/documents\\/(.+)$/);\n    if (!match) {\n      throw new Error(\"Invalid URI format\");\n    }\n\n    const documentName = match[1];\n    const content = await loadDocument(documentName);\n\n    return {\n      contents: [{\n        uri,\n        mimeType: \"text/plain\",\n        text: content\n      }]\n    };\n  }\n);\n\n// List available resources dynamically\nserver.registerResourceList(async () => {\n  const documents = await getAvailableDocuments();\n  return {\n    resources: documents.map(doc => ({\n      uri: `file://documents/${doc.name}`,\n      name: doc.name,\n      mimeType: \"text/plain\",\n      description: doc.description\n    }))\n  };\n});\n```\n\n**When to use Resources vs Tools:**\n- **Resources**: For data access with simple URI-based parameters\n- **Tools**: For complex operations requiring validation and business logic\n- **Resources**: When data is relatively static or template-based\n- **Tools**: When operations have side effects or complex workflows\n\n### Transport Options\n\nThe TypeScript SDK supports two main transport mechanisms:\n\n#### Streamable HTTP (Recommended for Remote Servers)\n\n```typescript\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport express from \"express\";\n\nconst app = express();\napp.use(express.json());\n\napp.post('/mcp', async (req, res) => {\n  // Create new transport for each request (stateless, prevents request ID collisions)\n  const transport = new StreamableHTTPServerTransport({\n    sessionIdGenerator: undefined,\n    enableJsonResponse: true\n  });\n\n  res.on('close', () => transport.close());\n\n  await server.connect(transport);\n  await transport.handleRequest(req, res, req.body);\n});\n\napp.listen(3000);\n```\n\n#### stdio (For Local Integrations)\n\n```typescript\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n```\n\n**Transport selection:**\n- **Streamable HTTP**: Web services, remote access, multiple clients\n- **stdio**: Command-line tools, local development, subprocess integration\n\n### Notification Support\n\nNotify clients when server state changes:\n\n```typescript\n// Notify when tools list changes\nserver.notification({\n  method: \"notifications/tools/list_changed\"\n});\n\n// Notify when resources change\nserver.notification({\n  method: \"notifications/resources/list_changed\"\n});\n```\n\nUse notifications sparingly - only when server capabilities genuinely change.\n\n---\n\n## Code Best Practices\n\n### Code Composability and Reusability\n\nYour implementation MUST prioritize composability and code reuse:\n\n1. **Extract Common Functionality**:\n   - Create reusable helper functions for operations used across multiple tools\n   - Build shared API clients for HTTP requests instead of duplicating code\n   - Centralize error handling logic in utility functions\n   - Extract business logic into dedicated functions that can be composed\n   - Extract shared markdown or JSON field selection & formatting functionality\n\n2. **Avoid Duplication**:\n   - NEVER copy-paste similar code between tools\n   - If you find yourself writing similar logic twice, extract it into a function\n   - Common operations like pagination, filtering, field selection, and formatting should be shared\n   - Authentication/authorization logic should be centralized\n\n## Building and Running\n\nAlways build your TypeScript code before running:\n\n```bash\n# Build the project\nnpm run build\n\n# Run the server\nnpm start\n\n# Development with auto-reload\nnpm run dev\n```\n\nAlways ensure `npm run build` completes successfully before considering the implementation complete.\n\n## Quality Checklist\n\nBefore finalizing your Node/TypeScript MCP server implementation, ensure:\n\n### Strategic Design\n- [ ] Tools enable complete workflows, not just API endpoint wrappers\n- [ ] Tool names reflect natural task subdivisions\n- [ ] Response formats optimize for agent context efficiency\n- [ ] Human-readable identifiers used where appropriate\n- [ ] Error messages guide agents toward correct usage\n\n### Implementation Quality\n- [ ] FOCUSED IMPLEMENTATION: Most important and valuable tools implemented\n- [ ] All tools registered using `registerTool` with complete configuration\n- [ ] All tools include `title`, `description`, `inputSchema`, and `annotations`\n- [ ] Annotations correctly set (readOnlyHint, destructiveHint, idempotentHint, openWorldHint)\n- [ ] All tools use Zod schemas for runtime input validation with `.strict()` enforcement\n- [ ] All Zod schemas have proper constraints and descriptive error messages\n- [ ] All tools have comprehensive descriptions with explicit input/output types\n- [ ] Descriptions include return value examples and complete schema documentation\n- [ ] Error messages are clear, actionable, and educational\n\n### TypeScript Quality\n- [ ] TypeScript interfaces are defined for all data structures\n- [ ] Strict TypeScript is enabled in tsconfig.json\n- [ ] No use of `any` type - use `unknown` or proper types instead\n- [ ] All async functions have explicit Promise<T> return types\n- [ ] Error handling uses proper type guards (e.g., `axios.isAxiosError`, `z.ZodError`)\n\n### Advanced Features (where applicable)\n- [ ] Resources registered for appropriate data endpoints\n- [ ] Appropriate transport configured (stdio or streamable HTTP)\n- [ ] Notifications implemented for dynamic server capabilities\n- [ ] Type-safe with SDK interfaces\n\n### Project Configuration\n- [ ] Package.json includes all necessary dependencies\n- [ ] Build script produces working JavaScript in dist/ directory\n- [ ] Main entry point is properly configured as dist/index.js\n- [ ] Server name follows format: `{service}-mcp-server`\n- [ ] tsconfig.json properly configured with strict mode\n\n### Code Quality\n- [ ] Pagination is properly implemented where applicable\n- [ ] Large responses check CHARACTER_LIMIT constant and truncate with clear messages\n- [ ] Filtering options are provided for potentially large result sets\n- [ ] All network operations handle timeouts and connection errors gracefully\n- [ ] Common functionality is extracted into reusable functions\n- [ ] Return types are consistent across similar operations\n\n### Testing and Build\n- [ ] `npm run build` completes successfully without errors\n- [ ] dist/index.js created and executable\n- [ ] Server runs: `node dist/index.js --help`\n- [ ] All imports resolve correctly\n- [ ] Sample tool calls work as expected\n","core/skills/builtin/mcp-builder/reference/python_mcp_server.md":"# Python MCP Server Implementation Guide\n\n## Overview\n\nThis document provides Python-specific best practices and examples for implementing MCP servers using the MCP Python SDK. It covers server setup, tool registration patterns, input validation with Pydantic, error handling, and complete working examples.\n\n---\n\n## Quick Reference\n\n### Key Imports\n```python\nfrom mcp.server.fastmcp import FastMCP\nfrom pydantic import BaseModel, Field, field_validator, ConfigDict\nfrom typing import Optional, List, Dict, Any\nfrom enum import Enum\nimport httpx\n```\n\n### Server Initialization\n```python\nmcp = FastMCP(\"service_mcp\")\n```\n\n### Tool Registration Pattern\n```python\n@mcp.tool(name=\"tool_name\", annotations={...})\nasync def tool_function(params: InputModel) -> str:\n    # Implementation\n    pass\n```\n\n---\n\n## MCP Python SDK and FastMCP\n\nThe official MCP Python SDK provides FastMCP, a high-level framework for building MCP servers. It provides:\n- Automatic description and inputSchema generation from function signatures and docstrings\n- Pydantic model integration for input validation\n- Decorator-based tool registration with `@mcp.tool`\n\n**For complete SDK documentation, use WebFetch to load:**\n`https://raw.githubusercontent.com/modelcontextprotocol/python-sdk/main/README.md`\n\n## Server Naming Convention\n\nPython MCP servers must follow this naming pattern:\n- **Format**: `{service}_mcp` (lowercase with underscores)\n- **Examples**: `github_mcp`, `jira_mcp`, `stripe_mcp`\n\nThe name should be:\n- General (not tied to specific features)\n- Descriptive of the service/API being integrated\n- Easy to infer from the task description\n- Without version numbers or dates\n\n## Tool Implementation\n\n### Tool Naming\n\nUse snake_case for tool names (e.g., \"search_users\", \"create_project\", \"get_channel_info\") with clear, action-oriented names.\n\n**Avoid Naming Conflicts**: Include the service context to prevent overlaps:\n- Use \"slack_send_message\" instead of just \"send_message\"\n- Use \"github_create_issue\" instead of just \"create_issue\"\n- Use \"asana_list_tasks\" instead of just \"list_tasks\"\n\n### Tool Structure with FastMCP\n\nTools are defined using the `@mcp.tool` decorator with Pydantic models for input validation:\n\n```python\nfrom pydantic import BaseModel, Field, ConfigDict\nfrom mcp.server.fastmcp import FastMCP\n\n# Initialize the MCP server\nmcp = FastMCP(\"example_mcp\")\n\n# Define Pydantic model for input validation\nclass ServiceToolInput(BaseModel):\n    '''Input model for service tool operation.'''\n    model_config = ConfigDict(\n        str_strip_whitespace=True,  # Auto-strip whitespace from strings\n        validate_assignment=True,    # Validate on assignment\n        extra='forbid'              # Forbid extra fields\n    )\n\n    param1: str = Field(..., description=\"First parameter description (e.g., 'user123', 'project-abc')\", min_length=1, max_length=100)\n    param2: Optional[int] = Field(default=None, description=\"Optional integer parameter with constraints\", ge=0, le=1000)\n    tags: Optional[List[str]] = Field(default_factory=list, description=\"List of tags to apply\", max_items=10)\n\n@mcp.tool(\n    name=\"service_tool_name\",\n    annotations={\n        \"title\": \"Human-Readable Tool Title\",\n        \"readOnlyHint\": True,     # Tool does not modify environment\n        \"destructiveHint\": False,  # Tool does not perform destructive operations\n        \"idempotentHint\": True,    # Repeated calls have no additional effect\n        \"openWorldHint\": False     # Tool does not interact with external entities\n    }\n)\nasync def service_tool_name(params: ServiceToolInput) -> str:\n    '''Tool description automatically becomes the 'description' field.\n\n    This tool performs a specific operation on the service. It validates all inputs\n    using the ServiceToolInput Pydantic model before processing.\n\n    Args:\n        params (ServiceToolInput): Validated input parameters containing:\n            - param1 (str): First parameter description\n            - param2 (Optional[int]): Optional parameter with default\n            - tags (Optional[List[str]]): List of tags\n\n    Returns:\n        str: JSON-formatted response containing operation results\n    '''\n    # Implementation here\n    pass\n```\n\n## Pydantic v2 Key Features\n\n- Use `model_config` instead of nested `Config` class\n- Use `field_validator` instead of deprecated `validator`\n- Use `model_dump()` instead of deprecated `dict()`\n- Validators require `@classmethod` decorator\n- Type hints are required for validator methods\n\n```python\nfrom pydantic import BaseModel, Field, field_validator, ConfigDict\n\nclass CreateUserInput(BaseModel):\n    model_config = ConfigDict(\n        str_strip_whitespace=True,\n        validate_assignment=True\n    )\n\n    name: str = Field(..., description=\"User's full name\", min_length=1, max_length=100)\n    email: str = Field(..., description=\"User's email address\", pattern=r'^[\\w\\.-]+@[\\w\\.-]+\\.\\w+$')\n    age: int = Field(..., description=\"User's age\", ge=0, le=150)\n\n    @field_validator('email')\n    @classmethod\n    def validate_email(cls, v: str) -> str:\n        if not v.strip():\n            raise ValueError(\"Email cannot be empty\")\n        return v.lower()\n```\n\n## Response Format Options\n\nSupport multiple output formats for flexibility:\n\n```python\nfrom enum import Enum\n\nclass ResponseFormat(str, Enum):\n    '''Output format for tool responses.'''\n    MARKDOWN = \"markdown\"\n    JSON = \"json\"\n\nclass UserSearchInput(BaseModel):\n    query: str = Field(..., description=\"Search query\")\n    response_format: ResponseFormat = Field(\n        default=ResponseFormat.MARKDOWN,\n        description=\"Output format: 'markdown' for human-readable or 'json' for machine-readable\"\n    )\n```\n\n**Markdown format**:\n- Use headers, lists, and formatting for clarity\n- Convert timestamps to human-readable format (e.g., \"2024-01-15 10:30:00 UTC\" instead of epoch)\n- Show display names with IDs in parentheses (e.g., \"@john.doe (U123456)\")\n- Omit verbose metadata (e.g., show only one profile image URL, not all sizes)\n- Group related information logically\n\n**JSON format**:\n- Return complete, structured data suitable for programmatic processing\n- Include all available fields and metadata\n- Use consistent field names and types\n\n## Pagination Implementation\n\nFor tools that list resources:\n\n```python\nclass ListInput(BaseModel):\n    limit: Optional[int] = Field(default=20, description=\"Maximum results to return\", ge=1, le=100)\n    offset: Optional[int] = Field(default=0, description=\"Number of results to skip for pagination\", ge=0)\n\nasync def list_items(params: ListInput) -> str:\n    # Make API request with pagination\n    data = await api_request(limit=params.limit, offset=params.offset)\n\n    # Return pagination info\n    response = {\n        \"total\": data[\"total\"],\n        \"count\": len(data[\"items\"]),\n        \"offset\": params.offset,\n        \"items\": data[\"items\"],\n        \"has_more\": data[\"total\"] > params.offset + len(data[\"items\"]),\n        \"next_offset\": params.offset + len(data[\"items\"]) if data[\"total\"] > params.offset + len(data[\"items\"]) else None\n    }\n    return json.dumps(response, indent=2)\n```\n\n## Error Handling\n\nProvide clear, actionable error messages:\n\n```python\ndef _handle_api_error(e: Exception) -> str:\n    '''Consistent error formatting across all tools.'''\n    if isinstance(e, httpx.HTTPStatusError):\n        if e.response.status_code == 404:\n            return \"Error: Resource not found. Please check the ID is correct.\"\n        elif e.response.status_code == 403:\n            return \"Error: Permission denied. You don't have access to this resource.\"\n        elif e.response.status_code == 429:\n            return \"Error: Rate limit exceeded. Please wait before making more requests.\"\n        return f\"Error: API request failed with status {e.response.status_code}\"\n    elif isinstance(e, httpx.TimeoutException):\n        return \"Error: Request timed out. Please try again.\"\n    return f\"Error: Unexpected error occurred: {type(e).__name__}\"\n```\n\n## Shared Utilities\n\nExtract common functionality into reusable functions:\n\n```python\n# Shared API request function\nasync def _make_api_request(endpoint: str, method: str = \"GET\", **kwargs) -> dict:\n    '''Reusable function for all API calls.'''\n    async with httpx.AsyncClient() as client:\n        response = await client.request(\n            method,\n            f\"{API_BASE_URL}/{endpoint}\",\n            timeout=30.0,\n            **kwargs\n        )\n        response.raise_for_status()\n        return response.json()\n```\n\n## Async/Await Best Practices\n\nAlways use async/await for network requests and I/O operations:\n\n```python\n# Good: Async network request\nasync def fetch_data(resource_id: str) -> dict:\n    async with httpx.AsyncClient() as client:\n        response = await client.get(f\"{API_URL}/resource/{resource_id}\")\n        response.raise_for_status()\n        return response.json()\n\n# Bad: Synchronous request\ndef fetch_data(resource_id: str) -> dict:\n    response = requests.get(f\"{API_URL}/resource/{resource_id}\")  # Blocks\n    return response.json()\n```\n\n## Type Hints\n\nUse type hints throughout:\n\n```python\nfrom typing import Optional, List, Dict, Any\n\nasync def get_user(user_id: str) -> Dict[str, Any]:\n    data = await fetch_user(user_id)\n    return {\"id\": data[\"id\"], \"name\": data[\"name\"]}\n```\n\n## Tool Docstrings\n\nEvery tool must have comprehensive docstrings with explicit type information:\n\n```python\nasync def search_users(params: UserSearchInput) -> str:\n    '''\n    Search for users in the Example system by name, email, or team.\n\n    This tool searches across all user profiles in the Example platform,\n    supporting partial matches and various search filters. It does NOT\n    create or modify users, only searches existing ones.\n\n    Args:\n        params (UserSearchInput): Validated input parameters containing:\n            - query (str): Search string to match against names/emails (e.g., \"john\", \"@example.com\", \"team:marketing\")\n            - limit (Optional[int]): Maximum results to return, between 1-100 (default: 20)\n            - offset (Optional[int]): Number of results to skip for pagination (default: 0)\n\n    Returns:\n        str: JSON-formatted string containing search results with the following schema:\n\n        Success response:\n        {\n            \"total\": int,           # Total number of matches found\n            \"count\": int,           # Number of results in this response\n            \"offset\": int,          # Current pagination offset\n            \"users\": [\n                {\n                    \"id\": str,      # User ID (e.g., \"U123456789\")\n                    \"name\": str,    # Full name (e.g., \"John Doe\")\n                    \"email\": str,   # Email address (e.g., \"john@example.com\")\n                    \"team\": str     # Team name (e.g., \"Marketing\") - optional\n                }\n            ]\n        }\n\n        Error response:\n        \"Error: <error message>\" or \"No users found matching '<query>'\"\n\n    Examples:\n        - Use when: \"Find all marketing team members\" -> params with query=\"team:marketing\"\n        - Use when: \"Search for John's account\" -> params with query=\"john\"\n        - Don't use when: You need to create a user (use example_create_user instead)\n        - Don't use when: You have a user ID and need full details (use example_get_user instead)\n\n    Error Handling:\n        - Input validation errors are handled by Pydantic model\n        - Returns \"Error: Rate limit exceeded\" if too many requests (429 status)\n        - Returns \"Error: Invalid API authentication\" if API key is invalid (401 status)\n        - Returns formatted list of results or \"No users found matching 'query'\"\n    '''\n```\n\n## Complete Example\n\nSee below for a complete Python MCP server example:\n\n```python\n#!/usr/bin/env python3\n'''\nMCP Server for Example Service.\n\nThis server provides tools to interact with Example API, including user search,\nproject management, and data export capabilities.\n'''\n\nfrom typing import Optional, List, Dict, Any\nfrom enum import Enum\nimport httpx\nfrom pydantic import BaseModel, Field, field_validator, ConfigDict\nfrom mcp.server.fastmcp import FastMCP\n\n# Initialize the MCP server\nmcp = FastMCP(\"example_mcp\")\n\n# Constants\nAPI_BASE_URL = \"https://api.example.com/v1\"\n\n# Enums\nclass ResponseFormat(str, Enum):\n    '''Output format for tool responses.'''\n    MARKDOWN = \"markdown\"\n    JSON = \"json\"\n\n# Pydantic Models for Input Validation\nclass UserSearchInput(BaseModel):\n    '''Input model for user search operations.'''\n    model_config = ConfigDict(\n        str_strip_whitespace=True,\n        validate_assignment=True\n    )\n\n    query: str = Field(..., description=\"Search string to match against names/emails\", min_length=2, max_length=200)\n    limit: Optional[int] = Field(default=20, description=\"Maximum results to return\", ge=1, le=100)\n    offset: Optional[int] = Field(default=0, description=\"Number of results to skip for pagination\", ge=0)\n    response_format: ResponseFormat = Field(default=ResponseFormat.MARKDOWN, description=\"Output format\")\n\n    @field_validator('query')\n    @classmethod\n    def validate_query(cls, v: str) -> str:\n        if not v.strip():\n            raise ValueError(\"Query cannot be empty or whitespace only\")\n        return v.strip()\n\n# Shared utility functions\nasync def _make_api_request(endpoint: str, method: str = \"GET\", **kwargs) -> dict:\n    '''Reusable function for all API calls.'''\n    async with httpx.AsyncClient() as client:\n        response = await client.request(\n            method,\n            f\"{API_BASE_URL}/{endpoint}\",\n            timeout=30.0,\n            **kwargs\n        )\n        response.raise_for_status()\n        return response.json()\n\ndef _handle_api_error(e: Exception) -> str:\n    '''Consistent error formatting across all tools.'''\n    if isinstance(e, httpx.HTTPStatusError):\n        if e.response.status_code == 404:\n            return \"Error: Resource not found. Please check the ID is correct.\"\n        elif e.response.status_code == 403:\n            return \"Error: Permission denied. You don't have access to this resource.\"\n        elif e.response.status_code == 429:\n            return \"Error: Rate limit exceeded. Please wait before making more requests.\"\n        return f\"Error: API request failed with status {e.response.status_code}\"\n    elif isinstance(e, httpx.TimeoutException):\n        return \"Error: Request timed out. Please try again.\"\n    return f\"Error: Unexpected error occurred: {type(e).__name__}\"\n\n# Tool definitions\n@mcp.tool(\n    name=\"example_search_users\",\n    annotations={\n        \"title\": \"Search Example Users\",\n        \"readOnlyHint\": True,\n        \"destructiveHint\": False,\n        \"idempotentHint\": True,\n        \"openWorldHint\": True\n    }\n)\nasync def example_search_users(params: UserSearchInput) -> str:\n    '''Search for users in the Example system by name, email, or team.\n\n    [Full docstring as shown above]\n    '''\n    try:\n        # Make API request using validated parameters\n        data = await _make_api_request(\n            \"users/search\",\n            params={\n                \"q\": params.query,\n                \"limit\": params.limit,\n                \"offset\": params.offset\n            }\n        )\n\n        users = data.get(\"users\", [])\n        total = data.get(\"total\", 0)\n\n        if not users:\n            return f\"No users found matching '{params.query}'\"\n\n        # Format response based on requested format\n        if params.response_format == ResponseFormat.MARKDOWN:\n            lines = [f\"# User Search Results: '{params.query}'\", \"\"]\n            lines.append(f\"Found {total} users (showing {len(users)})\")\n            lines.append(\"\")\n\n            for user in users:\n                lines.append(f\"## {user['name']} ({user['id']})\")\n                lines.append(f\"- **Email**: {user['email']}\")\n                if user.get('team'):\n                    lines.append(f\"- **Team**: {user['team']}\")\n                lines.append(\"\")\n\n            return \"\\n\".join(lines)\n\n        else:\n            # Machine-readable JSON format\n            import json\n            response = {\n                \"total\": total,\n                \"count\": len(users),\n                \"offset\": params.offset,\n                \"users\": users\n            }\n            return json.dumps(response, indent=2)\n\n    except Exception as e:\n        return _handle_api_error(e)\n\nif __name__ == \"__main__\":\n    mcp.run()\n```\n\n---\n\n## Advanced FastMCP Features\n\n### Context Parameter Injection\n\nFastMCP can automatically inject a `Context` parameter into tools for advanced capabilities like logging, progress reporting, resource reading, and user interaction:\n\n```python\nfrom mcp.server.fastmcp import FastMCP, Context\n\nmcp = FastMCP(\"example_mcp\")\n\n@mcp.tool()\nasync def advanced_search(query: str, ctx: Context) -> str:\n    '''Advanced tool with context access for logging and progress.'''\n\n    # Report progress for long operations\n    await ctx.report_progress(0.25, \"Starting search...\")\n\n    # Log information for debugging\n    await ctx.log_info(\"Processing query\", {\"query\": query, \"timestamp\": datetime.now()})\n\n    # Perform search\n    results = await search_api(query)\n    await ctx.report_progress(0.75, \"Formatting results...\")\n\n    # Access server configuration\n    server_name = ctx.fastmcp.name\n\n    return format_results(results)\n\n@mcp.tool()\nasync def interactive_tool(resource_id: str, ctx: Context) -> str:\n    '''Tool that can request additional input from users.'''\n\n    # Request sensitive information when needed\n    api_key = await ctx.elicit(\n        prompt=\"Please provide your API key:\",\n        input_type=\"password\"\n    )\n\n    # Use the provided key\n    return await api_call(resource_id, api_key)\n```\n\n**Context capabilities:**\n- `ctx.report_progress(progress, message)` - Report progress for long operations\n- `ctx.log_info(message, data)` / `ctx.log_error()` / `ctx.log_debug()` - Logging\n- `ctx.elicit(prompt, input_type)` - Request input from users\n- `ctx.fastmcp.name` - Access server configuration\n- `ctx.read_resource(uri)` - Read MCP resources\n\n### Resource Registration\n\nExpose data as resources for efficient, template-based access:\n\n```python\n@mcp.resource(\"file://documents/{name}\")\nasync def get_document(name: str) -> str:\n    '''Expose documents as MCP resources.\n\n    Resources are useful for static or semi-static data that doesn't\n    require complex parameters. They use URI templates for flexible access.\n    '''\n    document_path = f\"./docs/{name}\"\n    with open(document_path, \"r\") as f:\n        return f.read()\n\n@mcp.resource(\"config://settings/{key}\")\nasync def get_setting(key: str, ctx: Context) -> str:\n    '''Expose configuration as resources with context.'''\n    settings = await load_settings()\n    return json.dumps(settings.get(key, {}))\n```\n\n**When to use Resources vs Tools:**\n- **Resources**: For data access with simple parameters (URI templates)\n- **Tools**: For complex operations with validation and business logic\n\n### Structured Output Types\n\nFastMCP supports multiple return types beyond strings:\n\n```python\nfrom typing import TypedDict\nfrom dataclasses import dataclass\nfrom pydantic import BaseModel\n\n# TypedDict for structured returns\nclass UserData(TypedDict):\n    id: str\n    name: str\n    email: str\n\n@mcp.tool()\nasync def get_user_typed(user_id: str) -> UserData:\n    '''Returns structured data - FastMCP handles serialization.'''\n    return {\"id\": user_id, \"name\": \"John Doe\", \"email\": \"john@example.com\"}\n\n# Pydantic models for complex validation\nclass DetailedUser(BaseModel):\n    id: str\n    name: str\n    email: str\n    created_at: datetime\n    metadata: Dict[str, Any]\n\n@mcp.tool()\nasync def get_user_detailed(user_id: str) -> DetailedUser:\n    '''Returns Pydantic model - automatically generates schema.'''\n    user = await fetch_user(user_id)\n    return DetailedUser(**user)\n```\n\n### Lifespan Management\n\nInitialize resources that persist across requests:\n\n```python\nfrom contextlib import asynccontextmanager\n\n@asynccontextmanager\nasync def app_lifespan():\n    '''Manage resources that live for the server's lifetime.'''\n    # Initialize connections, load config, etc.\n    db = await connect_to_database()\n    config = load_configuration()\n\n    # Make available to all tools\n    yield {\"db\": db, \"config\": config}\n\n    # Cleanup on shutdown\n    await db.close()\n\nmcp = FastMCP(\"example_mcp\", lifespan=app_lifespan)\n\n@mcp.tool()\nasync def query_data(query: str, ctx: Context) -> str:\n    '''Access lifespan resources through context.'''\n    db = ctx.request_context.lifespan_state[\"db\"]\n    results = await db.query(query)\n    return format_results(results)\n```\n\n### Transport Options\n\nFastMCP supports two main transport mechanisms:\n\n```python\n# stdio transport (for local tools) - default\nif __name__ == \"__main__\":\n    mcp.run()\n\n# Streamable HTTP transport (for remote servers)\nif __name__ == \"__main__\":\n    mcp.run(transport=\"streamable_http\", port=8000)\n```\n\n**Transport selection:**\n- **stdio**: Command-line tools, local integrations, subprocess execution\n- **Streamable HTTP**: Web services, remote access, multiple clients\n\n---\n\n## Code Best Practices\n\n### Code Composability and Reusability\n\nYour implementation MUST prioritize composability and code reuse:\n\n1. **Extract Common Functionality**:\n   - Create reusable helper functions for operations used across multiple tools\n   - Build shared API clients for HTTP requests instead of duplicating code\n   - Centralize error handling logic in utility functions\n   - Extract business logic into dedicated functions that can be composed\n   - Extract shared markdown or JSON field selection & formatting functionality\n\n2. **Avoid Duplication**:\n   - NEVER copy-paste similar code between tools\n   - If you find yourself writing similar logic twice, extract it into a function\n   - Common operations like pagination, filtering, field selection, and formatting should be shared\n   - Authentication/authorization logic should be centralized\n\n### Python-Specific Best Practices\n\n1. **Use Type Hints**: Always include type annotations for function parameters and return values\n2. **Pydantic Models**: Define clear Pydantic models for all input validation\n3. **Avoid Manual Validation**: Let Pydantic handle input validation with constraints\n4. **Proper Imports**: Group imports (standard library, third-party, local)\n5. **Error Handling**: Use specific exception types (httpx.HTTPStatusError, not generic Exception)\n6. **Async Context Managers**: Use `async with` for resources that need cleanup\n7. **Constants**: Define module-level constants in UPPER_CASE\n\n## Quality Checklist\n\nBefore finalizing your Python MCP server implementation, ensure:\n\n### Strategic Design\n- [ ] Tools enable complete workflows, not just API endpoint wrappers\n- [ ] Tool names reflect natural task subdivisions\n- [ ] Response formats optimize for agent context efficiency\n- [ ] Human-readable identifiers used where appropriate\n- [ ] Error messages guide agents toward correct usage\n\n### Implementation Quality\n- [ ] FOCUSED IMPLEMENTATION: Most important and valuable tools implemented\n- [ ] All tools have descriptive names and documentation\n- [ ] Return types are consistent across similar operations\n- [ ] Error handling is implemented for all external calls\n- [ ] Server name follows format: `{service}_mcp`\n- [ ] All network operations use async/await\n- [ ] Common functionality is extracted into reusable functions\n- [ ] Error messages are clear, actionable, and educational\n- [ ] Outputs are properly validated and formatted\n\n### Tool Configuration\n- [ ] All tools implement 'name' and 'annotations' in the decorator\n- [ ] Annotations correctly set (readOnlyHint, destructiveHint, idempotentHint, openWorldHint)\n- [ ] All tools use Pydantic BaseModel for input validation with Field() definitions\n- [ ] All Pydantic Fields have explicit types and descriptions with constraints\n- [ ] All tools have comprehensive docstrings with explicit input/output types\n- [ ] Docstrings include complete schema structure for dict/JSON returns\n- [ ] Pydantic models handle input validation (no manual validation needed)\n\n### Advanced Features (where applicable)\n- [ ] Context injection used for logging, progress, or elicitation\n- [ ] Resources registered for appropriate data endpoints\n- [ ] Lifespan management implemented for persistent connections\n- [ ] Structured output types used (TypedDict, Pydantic models)\n- [ ] Appropriate transport configured (stdio or streamable HTTP)\n\n### Code Quality\n- [ ] File includes proper imports including Pydantic imports\n- [ ] Pagination is properly implemented where applicable\n- [ ] Filtering options are provided for potentially large result sets\n- [ ] All async functions are properly defined with `async def`\n- [ ] HTTP client usage follows async patterns with proper context managers\n- [ ] Type hints are used throughout the code\n- [ ] Constants are defined at module level in UPPER_CASE\n\n### Testing\n- [ ] Server runs successfully: `python your_server.py --help`\n- [ ] All imports resolve correctly\n- [ ] Sample tool calls work as expected\n- [ ] Error scenarios handled gracefully\n","core/skills/builtin/review-agent/SKILL.md":"---\nname: review-agent\ndescription: Perform a read-only, defect-first review of a specified code change and return every actionable finding. Use when another agent delegates review of uncommitted changes, a base-branch diff, a commit, or custom review instructions.\n---\n\n# Review Agent\n\nInspect the requested target directly and return every finding that the author would likely fix.\nDo not modify files, create commits, push branches, post review comments, or delegate the review\nto another agent.\n\n## Review the change\n\n1. Read the applicable `AGENTS.md` instructions.\n2. Inspect the complete diff for the requested target and enough surrounding code to understand\n   each changed path.\n3. Identify concrete regressions introduced by the change. Continue through the whole diff after\n   finding the first issue.\n4. Check the relevant tests and call sites to confirm that each finding is real and actionable.\n\nFor a base-branch review, compare the changes that would actually merge rather than diffing\ndirectly against the branch tip. Resolve the comparison ref to the branch's upstream when that\nupstream exists and is ahead of the local branch; otherwise use the local branch. Run\n`git merge-base HEAD <comparison-ref>`, then inspect `git diff <merge-base-sha>`. If the local\nbranch cannot be resolved, try its configured upstream explicitly before reporting that the target\nis unavailable.\n\nFlag an issue only when all of these are true:\n\n- It affects correctness, security, performance, or maintainability in a meaningful way.\n- It is discrete and actionable.\n- It was introduced by the reviewed change.\n- The affected scenario or call path can be demonstrated from the code.\n- The author would probably fix it if they knew about it.\n\nDo not flag speculative concerns, pre-existing problems, intentional behavior changes, or style\nnits that do not obscure the code.\n\n## Write the result\n\nPresent findings first, ordered by severity. Use one entry per issue in this form:\n\n`[P1] Imperative finding title — path/to/file.rs:line`\n\nFollow the title with one short paragraph explaining the affected scenario and why the behavior is\nwrong. Keep the cited range as small as possible and make sure it overlaps the reviewed diff.\n\nUse these priorities:\n\n- `P0`: universal release blocker or critical failure.\n- `P1`: urgent defect that should be fixed next.\n- `P2`: ordinary defect that should be fixed.\n- `P3`: low-impact issue that is still worth fixing.\n\nIf there are no qualifying findings, say `No findings.` Do not invent a finding to fill the result.\nAfter the findings, add a brief overall assessment and mention any material test gaps or residual\nrisks.\n","core/skills/builtin/review-agent/agents/openai.yaml":"interface:\n  display_name: \"Review Agent\"\n  short_description: \"Find actionable bugs in code changes\"\n  default_prompt: \"Use $review-agent to review the requested code changes and return actionable findings.\"\npolicy:\n  allow_implicit_invocation: false\n","core/skills/builtin/security-best-practices/SKILL.md":"---\nname: \"security-best-practices\"\ndescription: \"Perform language and framework specific security best-practice reviews and suggest improvements. Trigger only when the user explicitly requests security best practices guidance, a security review/report, or secure-by-default coding help. Trigger only for supported languages (python, javascript/typescript, go). Do not trigger for general code review, debugging, or non-security tasks.\"\n---\n\n# Security Best Practices\n\n## Overview\n\nThis skill provides a description of how to identify the language and frameworks used by the current context, and then to load information from this skill's references directory about the security best practices for this language and or frameworks.\n\nThis information, if present, can be used to write new secure by default code, or to passively detect major issues within existing code, or (if requested by the user) provide a vulnerability report and suggest fixes.\n\n## Workflow\n\nThe initial step for this skill is to identify ALL languages and ALL frameworks which you are being asked to use or already exist in the scope of the project you are working in. Focus on the primary core frameworks. Often you will want to identify both frontend and backend languages and frameworks.\n\nThen check this skill's references directory to see if there are any relevant documentation for the language and or frameworks. Make sure you read ALL reference files which relate to the specific framework or language. The format of the filenames is `<language>-<framework>-<stack>-security.md`. You should also check if there is a `<language>-general-<stack>-security.md` which is agnostic to the framework you may be using.\n\nIf working on a web application which includes a frontend and a backend, make sure you have checked for reference documents for BOTH the frontend and backend!\n\nIf you are asked to make a web app which will include both a frontend and backend, but the frontend framework is not specified, also check out `javascript-general-web-frontend-security.md`. It is important that you understand how to secure both the frontend and backend.\n\nIf no relevant information is available in the skill's references directory, think a little bit about what you know about the language, the framework, and all well known security best practices for it. If you are unsure you can try to search online for documentation on security best practices.\n\nFrom there it can operate in a few ways.\n\n1. The primary mode is to just use the information to write secure by default code from this point forward. This is useful for starting a new project or when writing new code.\n\n2. The secondary mode is to passively detect vulnerabilities while working in the project and writing code for the user. Critical or very important vulnerabilities or major issues going against security guidance can be flagged and the user can be told about them. This passive mode should focus on the largest impact vulnerabilities and secure defaults.\n\n3. The user can ask for a security report or to improve the security of the codebase. In this case a full report should be produced describe anyways the project fails to follow security best practices guidance. The report should be prioritized and have clear sections of severity and urgency. Then offer to start working on fixes for these issues. See #fixes below.\n\n## Workflow Decision Tree\n\n- If the language/framework is unclear, inspect the repo to determine it and list your evidence.\n- If matching guidance exists in `references/`, load only the relevant files and follow their instructions.\n- If no matching guidance exists, consider if you know any well known security best practices for the chosen language and or frameworks, but if asked to generate a report, let the user know that concrete guidance is not available (you can still generate the report or detect for sure critical vulnerabilities)\n\n# Overrides\n\nWhile these references contain the security best practices for languages and frameworks, customers may have cases where they need to bypass or override these practices. Pay attention to specific rules and instructions in the project's documentation and prompt files which may require you to override certain best practices. When overriding a best practice, you MAY report it to the user, but do not fight with them. If a security best practice needs to be bypassed / ignored for some project specific reason, you can also suggest to add documentation about this to the project so it is clear why the best practice is not being followed and to follow that bypass in the future.\n\n# Report Format\n\nWhen producing a report, you should write the report as a markdown file in `security_best_practices_report.md` or some other location if provided by the user. You can ask the user where they would like the report to be written to.\n\nThe report should have a short executive summary at the top.\n\nThe report should be clearly delineated into multiple sections based on severity of the vulnerability. The report should focus on the most critical findings as these have the highest impact for the user. All findings should be noted with an numeric ID to make them easier to reference.\n\nFor critical findings include a one sentence impact statement.\n\nOnce the report is written, also report it to the user directly, although you may be less verbose. You can offer to explain any of the findings or the reasons behind the security best practices guidance if the user wants more info on any findings.\n\nImportant: When referencing code in the report, make sure to find and include line numbers for the code you are referencing.\n\nAfter you write the report file, summarize the findings to the user.\n\nAlso tell the user where the final report was written to\n\n# Fixes\n\nIf you produced a report, let the user read the report and ask to begin performing fixes.\n\nIf you passively found a critical finding, notify the user and ask if they would like you to fix this finding.\n\nWhen producing fixes, focus on fixing a single finding at a time. The fixes should have concise clear comments explaining that the new code is based on the specific security best practice, and perhaps a very short reason why it would be dangerous to not do it in this way.\n\nAlways consider if the changes you want to make will impact the functionality of the user's code. Consider if the changes may cause regressions with how the project works currently. It is often the case that insecure code is relied on for other reasons (and this is why insecure code lives on for so long). Avoid breaking the user's project as this may make them not want to apply security fixes in the future. It is better to write a well thought out, well informed by the rest of the project, fix, then a quick slapdash change.\n\nAlways follow any normal change or commit flow the user has configured. If making git commits, provide clear commit messages explaining this is to align with security best practices. Try to avoid bunching a number of unrelated findings into a single commit.\n\nAlways follow any normal testing flows the user has configured (if any) to confirm that your changes are not introducing regressions. Consider the second order impacts the changes may have and inform the user before making them if there are any.\n\n# General Security Advice\n\nBelow is a few bits of secure coding advice that applies to almost any language or framework.\n\n### Avoid Using Incrementing IDs for Public IDs of Resources\n\nWhen assigning an ID for some resource, which will then be used by exposed to the internet, avoid using small auto-incrementing IDs. Use longer, random UUID4 or random hex string instead. This will prevent users from learning the quantity of a resource and being able to guess resource IDs.\n\n### A note on TLS\n\nWhile TLS is important for production deployments, most development work will be with TLS disabled or provided by some out-of-scope TLS proxy. Due to this, be very careful about not reporting lack of TLS as a security issue. Also be very careful around use of \"secure\" cookies. They should only be set if the application will actually be over TLS. If they are set on non-TLS applications (such as when deployed for local dev or testing), it will break the application. You can provide a env or other flag to override setting secure as a way to keep it off until on a TLS production deployment. Additionally avoid recommending HSTS. It is dangerous to use without full understanding of the lasting impacts (can cause major outages and user lockout) and it is not generally recommended for the scope of projects being reviewed by codex.\n","core/skills/builtin/security-best-practices/agents/openai.yaml":"interface:\n  display_name: \"Security Best Practices\"\n  short_description: \"Security reviews and secure-by-default guidance\"\n  default_prompt: \"Review this codebase for security best practices and suggest secure-by-default improvements.\"\n","core/skills/builtin/security-best-practices/references/golang-general-backend-security.md":"# Go (Golang) Security Spec (Go 1.25.x, Standard Library, net/http)\n\nThis document is designed as a **security spec** that supports:\n1) **Secure-by-default code generation** for new Go code.\n2) **Security review / vulnerability hunting** in existing Go code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n--------------------------------------------------------------------\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n- MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session cookies, JWTs, database URLs with credentials, signing keys, client secrets).\n- MUST NOT “fix” security by disabling protections (e.g., `InsecureSkipVerify`, `GOSUMDB=off` for public modules, wildcard CORS + credentials, removing auth checks, disabling CSRF defenses on cookie-auth apps).\n- MUST provide **evidence-based findings** during audits: cite file paths, code snippets, build/deploy configs, and concrete values that justify the claim.\n- MUST treat uncertainty honestly: if a control might exist in infrastructure (reverse proxy, WAF, service mesh, platform config), report it as “not visible in app code; verify at runtime/config.”\n- MUST keep fixes minimal, correct, and production-safe; avoid introducing breaking changes without warning (especially around auth/session flows, and proxies).\n\n--------------------------------------------------------------------\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\nWhen asked to write new Go code or modify existing code:\n- MUST follow every **MUST** requirement in this spec.\n- SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n- MUST prefer safe-by-default APIs and proven libraries over custom security code.\n- MUST avoid introducing new risky sinks (shell execution, dynamic template execution, serving user files as HTML, unsafe redirects, weak crypto, unbounded parsing, etc.).\n\n### 1.2 Passive review mode (always on while editing)\nWhile working anywhere in a Go repo (even if the user did not ask for a security scan):\n- MUST “notice” violations of this spec in touched/nearby code.\n- SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n- MUST systematically search the codebase for violations of this spec.\n- MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n1) Build/deploy entrypoints: `main.go`, `cmd/*`, Dockerfiles, Kubernetes manifests, systemd units, CI workflows.\n2) Go toolchain & dependency policy: Go version, modules, `go.mod/go.sum`, proxy/sumdb settings, govulncheck usage.\n3) Secret management and config loading (env, files, secret stores) + logging patterns.\n4) HTTP server configuration (timeouts, body limits, proxy trust, security headers).\n5) AuthN/AuthZ boundaries, session/cookie settings, token validation.\n6) CSRF protections for cookie-authenticated state-changing endpoints.\n7) Template usage and output encoding (XSS), and any “render template from string” behavior (SSTI).\n8) File handling (uploads/downloads/path traversal/temp files), static file serving.\n9) Injection sinks: SQL, OS command execution, SSRF/outbound fetch, open redirects.\n10) Concurrency/resource exhaustion (unbounded goroutines/queues, missing timeouts/contexts).\n11) Use of `unsafe` / `cgo` / `reflect` in security-sensitive paths.\n12) Debug/diagnostic endpoints (pprof/expvar/metrics) exposure.\n13) Cryptography usage (randomness, password hashing).\n\n--------------------------------------------------------------------\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\nExamples include:\n- `*http.Request` fields: `r.URL.Path`, `r.URL.RawQuery`, `r.Form`, `r.PostForm`, headers, cookies, `r.Body`\n- Path parameters from routers (including values extracted from URL paths)\n- JSON/XML/YAML bodies, multipart form parts, uploaded files\n- Any data from external systems (webhooks, third-party APIs, message queues)\n- Any persisted user content (DB rows) that originated from users\n- Configuration values that might be attacker-influenced in some deployments (headers set by upstream proxies, environment variables in multi-tenant systems)\n\n### 2.2 State-changing request\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook send), or initiate privileged actions.\n\n### 2.3 Required audit finding format\nFor each issue found, output:\n\n- Rule ID:\n- Severity: Critical / High / Medium / Low\n- Location: file path + function/handler name + line(s)\n- Evidence: the exact code/config snippet\n- Impact: what could go wrong, who can exploit it\n- Fix: safe change (prefer minimal diff)\n- Mitigation: defense-in-depth if immediate fix is hard\n- False positive notes: what to verify if uncertain (edge configs, proxy behavior, auth assumptions)\n\n--------------------------------------------------------------------\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common Go misconfigurations.\n\n### 3.1 Toolchain, patching, and dependency hygiene (MUST)\n- MUST run a supported Go major version and keep to the latest patch releases.\n- MUST treat Go standard library patch releases as security-relevant (many security fixes land in stdlib components like `net/http`, `crypto/*`, parsing packages).\n- MUST use Go modules with committed `go.mod` and `go.sum`.\n- MUST NOT disable module authenticity mechanisms for public modules (checksum DB) unless you have a controlled, documented replacement.\n- MUST run `govulncheck` (source scan and/or binary scan) in CI and address findings.\n\n### 3.2 HTTP server baseline (MUST for network-facing services)\nIf the program serves HTTP (directly or via a framework built on `net/http`):\n- MUST configure an `http.Server` with explicit timeouts and header limits.\n- MUST set request body size limits (global and per-route as needed).\n- MUST avoid exposing diagnostic endpoints (pprof/expvar) publicly.\n- SHOULD set a consistent set of security headers (or verify they are set at the edge).\n- MUST set cookie security attributes for any cookies you issue.\n- SHOULD implement rate limiting and abuse controls for auth and expensive endpoints.\n\nIllustrative baseline skeleton (adjust to your project):\n- Create a dedicated mux (avoid implicit global defaults unless intentionally managed).\n- Wrap handlers with: panic-safe error handling, request ID, logging, auth, and limits.\n\n--------------------------------------------------------------------\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### GO-DEPLOY-001: Keep the Go toolchain and standard library updated (security releases)\nSeverity: Medium\n\nNOTE: Upgrading dependencies and the core Go version can break projects in unexpected ways. Focus on only security-critical dependencies and if noticed, let the user know rather than upgrading automatically.\n\nRequired:\n- MUST run a supported Go major release and apply patch releases promptly.\n- SHOULD treat patch releases as security-relevant, even if your application code didn’t change.\n\nInsecure patterns:\n- Production builds pinned to old Go versions without a patching process.\n- Docker images like `golang:1.xx` or custom base images that are not updated regularly.\n- CI pipelines that intentionally suppress Go updates.\n\nDetection hints:\n- Inspect CI (`.github/workflows`, `gitlab-ci.yml`, etc.) for `go-version:` or toolchain setup.\n- Inspect Dockerfiles for `FROM golang:` tags.\n- Inspect `go.mod` `go` directive and any toolchain pinning.\n\nFix:\n- Upgrade to the latest patch of a supported Go version.\n- Add an automated check (CI) that fails when Go is below an approved minimum.\n\nNotes:\n- Go publishes regular minor releases that frequently include security fixes across standard library packages.\n\n---\n\n### GO-SUPPLY-001: Go module authenticity MUST NOT be disabled for public dependencies\nSeverity: High\n\nRequired:\n- MUST keep module checksum verification enabled for public modules.\n- SHOULD commit `go.sum` and treat changes as security-sensitive.\n- MUST NOT use insecure module fetching settings for public modules.\n- MAY configure private module behavior using `GOPRIVATE`/`GONOSUMDB` for private repos, but must do so narrowly and intentionally.\n\nInsecure patterns:\n- `GOSUMDB=off` in CI or production build environments for public modules.\n- `GONOSUMDB=*` or overly broad patterns that effectively disable verification.\n- `GOINSECURE=*` or broad `GOINSECURE` patterns for public modules.\n- `GOPROXY=direct` everywhere without a clear policy.\n\nDetection hints:\n- Search build configs for `GOSUMDB`, `GONOSUMDB`, `GOINSECURE`, `GOPROXY`, `GOPRIVATE`.\n- Look for documentation/scripts that recommend disabling checksum DB “to make builds work”.\n\nFix:\n- Restore defaults for public module verification.\n- For private modules:\n  - Set `GOPRIVATE=your.private.domain/*`\n  - Configure an internal proxy or direct fetching, and restrict `GONOSUMDB` to private patterns only.\n\nNotes:\n- Disabling checksum verification removes an important integrity layer against targeted or compromised upstream delivery.\n\n---\n\n### GO-CONFIG-001: Secrets must be externalized and never logged or committed\nSeverity: High (Critical if credentials are committed)\n\nRequired:\n- MUST load secrets from environment variables, secret managers, or secure config files with restricted permissions.\n- MUST NOT hard-code secrets in Go source, test fixtures that may reach production, or build args.\n- MUST NOT log secrets or full credential-bearing connection strings.\n- SHOULD fail closed in production if required secrets are missing.\n\nInsecure patterns:\n- String constants containing tokens/keys/passwords.\n- `.env` files or config files with secrets committed to repo.\n- Logging `os.Environ()`, dumping full configs, or printing DSNs.\n\nDetection hints:\n- Search for suspicious literals (`API_KEY`, `SECRET`, `PASSWORD`, `Authorization:`).\n- Inspect config loaders and logging statements.\n- Inspect CI logs or debug print paths.\n\nFix:\n- Move secrets to a secret store / environment variables.\n- Redact sensitive fields in logs.\n- Add secret scanning to CI and pre-commit.\n\n---\n\n### GO-HTTP-001: HTTP servers MUST set timeouts and MaxHeaderBytes\nSeverity: High (DoS risk)\n\nRequired:\n- MUST set: `ReadHeaderTimeout`, and SHOULD set `ReadTimeout`, `WriteTimeout`, `IdleTimeout` as appropriate for the service.\n- MUST set `MaxHeaderBytes` to a justified limit for your application.\n- MUST NOT rely on default zero-values for timeouts in production for internet-facing servers.\n\nInsecure patterns:\n- `http.ListenAndServe(\":8080\", handler)` with a default `http.Server` (no explicit timeouts).\n- `&http.Server{}` with timeouts left at zero.\n- Missing `MaxHeaderBytes`.\n\nDetection hints:\n- Search for `http.ListenAndServe(`, `ListenAndServeTLS(`, `Server{` and inspect configured fields.\n- Check for reverse proxies; even with a proxy, app-level timeouts still matter.\n\nFix:\n- Use `http.Server{ReadHeaderTimeout: ..., ReadTimeout: ..., WriteTimeout: ..., IdleTimeout: ..., MaxHeaderBytes: ...}`.\n- Calibrate timeouts per endpoint type (streaming vs JSON APIs).\n\nNotes:\n- Net/http documents that these timeouts exist and that zero/negative values mean “no timeout”; production services should choose explicit values.\n\n---\n\n### GO-HTTP-002: Request body and multipart parsing MUST be size-bounded\nSeverity: Medium (DoS risk; can be High for upload-heavy apps)\n\nRequired:\n- MUST enforce a global maximum request body size for endpoints that accept bodies.\n- MUST enforce strict multipart upload limits and avoid unbounded form parsing.\n- SHOULD enforce per-route limits when some endpoints legitimately need larger bodies.\n- SHOULD set upstream (proxy) limits as defense-in-depth.\n\nInsecure patterns:\n- Reading `r.Body` with `io.ReadAll(r.Body)` without a size cap.\n- Calling `r.ParseMultipartForm(...)` with overly large limits (or forgetting size controls).\n- Accepting file uploads with no limits on file size, number of parts, or total body size.\n\nDetection hints:\n- Search for `io.ReadAll(r.Body)`, `json.NewDecoder(r.Body)`, `ParseMultipartForm`, `FormFile`, `multipart`.\n- Look for missing `http.MaxBytesReader` or equivalent per-handler limiting.\n- Look for “upload” endpoints and check limits.\n\nFix:\n- Wrap request bodies with `http.MaxBytesReader(w, r.Body, maxBytes)` before parsing.\n- For multipart, set conservative limits and validate file sizes/part counts explicitly.\n- Set proxy limits (e.g., at ingress) in addition to app limits.\n\nNotes:\n- There are known vulnerability classes and advisories related to excessive resource consumption in multipart/form parsing; treat unbounded parsing as a security issue.\n\n---\n\n### GO-DEPLOY-002: Diagnostic endpoints (pprof/expvar/metrics) MUST NOT be publicly exposed\nSeverity: High\n\nNOTE: This only applies to production configurations. These endpoints are often used for debug or dev endpoints. If found, confirm that it would be reachable from the actual production deployment.\n\nRequired:\n- MUST NOT expose `net/http/pprof` handlers on a public internet-facing listener without strong access controls.\n- SHOULD run diagnostics on a separate, internal-only listener (loopback/VPC-only) and require auth.\n- MUST review what diagnostic endpoints reveal (stack traces, memory, command lines, environment, internal URLs).\n\nInsecure patterns:\n- Side-effect import `import _ \"net/http/pprof\"` in a server binary with a public mux.\n- `/debug/pprof/*` reachable without auth.\n- `/debug/vars` (expvar) reachable without auth.\n\nDetection hints:\n- Search for `net/http/pprof` imports (including blank imports).\n- Search for route prefixes `/debug/pprof`, `/debug/vars`.\n- Check whether `http.DefaultServeMux` is used and whether any debug handlers register globally.\n\nFix:\n- Remove diagnostics from production builds, or bind them to an internal-only listener.\n- Add strong authentication/authorization (and ideally network-level restrictions).\n\nNotes:\n- pprof is typically imported for its side effect of registering HTTP handlers under `/debug/pprof/`.\n\n---\n\n### GO-HTTP-003: Reverse proxy and forwarded header trust MUST be explicit\nSeverity: High (auth, URL generation, logging/auditing correctness)\n\nRequired:\n- If behind a reverse proxy, MUST define which proxy is trusted and how client IP/scheme/host are derived.\n- MUST NOT trust `X-Forwarded-For`, `X-Forwarded-Proto`, `Forwarded`, or similar headers from the open internet.\n- MUST ensure “secure cookie” logic, redirects, and absolute URL generation do not rely on spoofable headers.\n\nInsecure patterns:\n- Using `r.Header.Get(\"X-Forwarded-For\")` as the client IP without validating the proxy boundary.\n- Deriving “is HTTPS” from `X-Forwarded-Proto` without confirming it came from a trusted proxy.\n- Using forwarded `Host` values for password reset links without allowlisting.\n\nDetection hints:\n- Search for `X-Forwarded-For`, `X-Forwarded-Proto`, `Forwarded`, `Real-IP`, and any custom “client IP” helpers.\n- Inspect ingress/proxy configs; if not visible, mark as “verify at edge”.\n\nFix:\n- Enforce proxy trust at the edge and in app:\n  - Accept forwarded headers only from known proxy IP ranges.\n  - Prefer platform-provided mechanisms where available.\n- If generating external links, use a configured allowlisted canonical origin (not the request’s Host header).\n\n---\n\n### GO-HTTP-004: Security headers SHOULD be set (in app or at the edge)\nSeverity: Medium\n\nRequired (typical web app serving browsers):\n- SHOULD set:\n  - `Content-Security-Policy` (CSP) appropriate to the app. NOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n  - `X-Content-Type-Options: nosniff`\n  - Clickjacking protection (`X-Frame-Options` and/or CSP `frame-ancestors`)\n  - `Referrer-Policy` and `Permissions-Policy` where appropriate\n- MUST ensure cookies have secure attributes (see GO-HTTP-005).\n\nNOTE:\n- These headers may be set via reverse proxy/CDN; if not visible in app code, report as “verify at edge”.\n\nInsecure patterns:\n- No security headers anywhere (app or edge) for a browser-facing app.\n- CSP missing for apps rendering untrusted content.\n\nDetection hints:\n- Search for middleware setting headers: `w.Header().Set(\"Content-Security-Policy\", ...)`, etc.\n- Search for reverse proxy config that sets headers.\n\nFix:\n- Add centralized header middleware in Go, or configure at the edge.\n- Keep CSP realistic; avoid `unsafe-inline` where possible.\n\n---\n\n### GO-HTTP-005: Cookies MUST use secure attributes in production\nSeverity: Medium\n\nRequired (production, HTTPS):\n- MUST set `Secure` on cookies that carry auth/session state. IMPORTANT NOTE: Only set `Secure` in production environment when TLS is configured. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n- MUST set `HttpOnly` on auth/session cookies.\n- SHOULD set `SameSite=Lax` by default (or `Strict` if compatible), and only use `None` when necessary (and only with `Secure`).\n- SHOULD set bounded lifetimes (`Max-Age`/`Expires`) appropriate to the app.\n\nInsecure patterns:\n- Setting auth/session cookies without `Secure` in HTTPS deployments.\n- Cookies without `HttpOnly` for session identifiers.\n- `SameSite=None` for cookie-authenticated apps without a strong CSRF strategy.\n\nDetection hints:\n- Search for `http.SetCookie`, `&http.Cookie{`, `Set-Cookie`.\n- Inspect cookie flags in auth/session code.\n\nFix:\n- Set the correct fields on `http.Cookie` and centralize cookie creation.\n\nNotes:\n- SameSite is defense-in-depth and does not replace CSRF protections for cookie-auth apps.\n\n---\n\n### GO-HTTP-006: Cookie-authenticated state-changing endpoints MUST be CSRF-protected\nSeverity: High\n\n- IMPORTANT NOTE: If cookies are not used for auth (e.g., pure bearer token in Authorization header with no ambient cookies), CSRF is not a risk for those endpoints.\n\nRequired:\n- MUST protect all state-changing endpoints (POST/PUT/PATCH/DELETE) that rely on cookies for authentication.\n- SHOULD use a well-tested CSRF library/middleware rather than rolling your own.\n- MAY use additional defenses (Origin/Referer checks, Fetch Metadata, SameSite cookies), but tokens remain the primary defense for cookie-authenticated apps.\nIf tokens are impractical, or for small applications:\n* MUST at a minimum require a custom header to be set and set the session cookie SESSION_COOKIE_SAMESITE=lax, as this is the strongest method besides requiring a form token, and may be much easier to implement.\n\n\nInsecure patterns:\n- Cookie-authenticated JSON endpoints that mutate state with no CSRF checks.\n- Using GET for state-changing actions.\n\nDetection hints:\n- Enumerate all non-GET routes and identify auth mechanism.\n- Look for CSRF middleware usage; if absent, treat as suspicious in browser-facing apps.\n\nFix:\n- Add CSRF middleware and ensure it covers all state-changing routes.\n- If the service is an API intended for non-browser clients, avoid cookie auth; use Authorization headers.\n\n---\n\n### GO-HTTP-007: CORS must be explicit and least-privilege\nSeverity: Medium (High if misconfigured with credentials)\n\nRequired:\n- If CORS is not needed, MUST keep it disabled.\n- If CORS is needed:\n  - MUST allowlist trusted origins (do not reflect arbitrary origins)\n  - MUST be careful with credentialed requests; do not combine broad origins with cookies\n  - SHOULD restrict allowed methods/headers\n\nInsecure patterns:\n- `Access-Control-Allow-Origin: *` paired with cookies (`Access-Control-Allow-Credentials: true`).\n- Reflecting `Origin` without validation.\n\nDetection hints:\n- Search for `Access-Control-Allow-` header setting.\n- Search for CORS middleware configuration.\n\nFix:\n- Implement strict origin allowlists and minimal methods/headers.\n- Ensure cookie-auth endpoints are not exposed cross-origin unless required.\n\n---\n\n### GO-XSS-001: Use html/template and avoid bypassing auto-escaping with untrusted data\nSeverity: High\n\nRequired:\n- MUST use `html/template` for HTML rendering (not `text/template`).\n- MUST NOT convert untrusted data into “trusted” template types (`template.HTML`, `template.JS`, `template.URL`, etc.).\n- SHOULD keep templates static and controlled by developers; treat dynamic templates as high risk.\n- MUST NOT serve user-uploaded HTML/JS as active content unless explicitly intended and safely sandboxed.\n\nInsecure patterns:\n- `text/template` used to generate HTML.\n- Using `template.HTML(userInput)` or similar typed wrappers.\n- Directly writing unescaped user content into HTML responses.\n\nDetection hints:\n- Search for `text/template`, `template.New(...).Parse(...)`, and typed wrappers like `template.HTML(`.\n- Inspect handlers that return HTML with string concatenation.\n\nFix:\n- Use `html/template` and pass untrusted data as data, not markup.\n- If you must allow limited HTML, use a vetted HTML sanitizer and still be careful with attributes/URLs.\n\n---\n\n### GO-SSTI-001: Never parse/execute templates from untrusted input (SSTI)\nSeverity: Critical\n\nRequired:\n- MUST NOT call `template.Parse` / `template.ParseFiles` / `template.New(...).Parse(...)` on template text influenced by untrusted input.\n- MUST treat “user-defined templates” as a special high-risk design:\n  - MUST use heavy sandboxing and strict allowlists\n  - MUST isolate execution (process/container boundary) if truly required\n\nInsecure patterns:\n- `tmpl := template.Must(template.New(\"x\").Parse(r.FormValue(\"tmpl\")))`\n- Reading templates from uploads / DB entries and executing them in the same trust domain as server code.\n\nDetection hints:\n- Search for `.Parse(` and trace the origin of the template string.\n- Look for “custom email templates”, “user theming templates”, etc.\n\nFix:\n- Replace with safe substitution mechanisms (no code execution).\n- If templates must be user-controlled, isolate and sandbox aggressively.\n\n---\n\n### GO-PATH-001: Prevent path traversal and unsafe file serving\nSeverity: High\n\nRequired:\n- MUST NOT pass user-controlled paths to `os.Open`, `os.ReadFile`, `http.ServeFile`, or `http.FileServer` without strict validation and base-dir enforcement.\n- MUST treat `..`, absolute paths, and OS-specific path tricks as hostile input.\n- SHOULD store user uploads outside any static web root; serve through controlled handlers.\n- MUST avoid directory listing for sensitive file trees.\n\nInsecure patterns:\n- `http.ServeFile(w, r, r.URL.Query().Get(\"path\"))`\n- `os.Open(filepath.Join(baseDir, userPath))` without checking that the result stays under `baseDir`\n- `http.FileServer(http.Dir(\".\"))` serving the project root or user-writable directories\n\nDetection hints:\n- Search for `ServeFile(`, `FileServer(`, `http.Dir(`, `os.Open(`, `ReadFile(`, `filepath.Join(`.\n- Trace whether path components come from request/DB.\n\nFix:\n- Use an allowlist of file identifiers (e.g., database IDs) mapped to server-side paths.\n- Enforce base directory containment after cleaning and joining.\n- Serve active formats as downloads (`Content-Disposition: attachment`) unless explicitly intended.\n\n---\n\n### GO-UPLOAD-001: File uploads must be validated, stored safely, and served safely\nSeverity: High\n\nRequired:\n- MUST enforce upload size limits (app + edge).\n- MUST validate file type using allowlists and content checks (not only extensions).\n- MUST store uploads outside executable/static roots when possible.\n- SHOULD generate server-side filenames (random IDs) and avoid trusting original names.\n- MUST serve potentially active formats safely (download attachment) unless explicitly intended.\n\nInsecure patterns:\n- Accepting arbitrary file types and serving them back inline.\n- Using user-supplied filename as storage path.\n- Missing size/type validation.\n\nDetection hints:\n- Search for `multipart`, `FormFile`, `ParseMultipartForm`, `io.Copy` to disk.\n- Check where files are stored and how they are served.\n\nFix:\n- Implement allowlist validation + safe storage + safe serving.\n- Add scanning/quarantine workflows where applicable.\n\n---\n\n### GO-INJECT-001: Prevent SQL injection (parameterized queries / ORM)\nSeverity: High\n\nRequired:\n- MUST use parameterized queries or an ORM that parameterizes under the hood.\n- MUST NOT build SQL by string concatenation / `fmt.Sprintf` / string interpolation with untrusted input.\n\nInsecure patterns:\n- `fmt.Sprintf(\"SELECT ... WHERE id=%s\", r.URL.Query().Get(\"id\"))`\n- `query := \"UPDATE users SET role='\" + role + \"' WHERE id=\" + id`\n\nDetection hints:\n- Grep for `SELECT`, `INSERT`, `UPDATE`, `DELETE` and check how query strings are built.\n- Trace untrusted data into `db.Query`, `db.Exec`, `QueryRow`, etc.\n\nFix:\n- Replace with placeholders (`?`, `$1`, etc.) and pass parameters separately.\n- Validate and type-check IDs before use.\n\n---\n\n### GO-INJECT-002: Prevent OS command injection; avoid shelling out with untrusted input\nSeverity: Critical to High (depends on exposure)\n\nRequired:\n- MUST avoid executing external commands with attacker-controlled strings.\n- If subprocess is necessary:\n  - MUST use `exec.CommandContext` with an argument list (not `sh -c`).\n  - MUST NOT pass untrusted input to a shell (`bash -c`, `sh -c`, PowerShell).\n  - SHOULD use strict allowlists for any variable component (subcommand, flags, filenames).\n- MUST assume CLI tools may interpret attacker-controlled args as flags or special values.\n\nInsecure patterns:\n- `exec.Command(\"sh\", \"-c\", userString)`\n- `exec.Command(\"bash\", \"-c\", fmt.Sprintf(\"tool %s\", user))`\n- Calling the shell to get glob expansion for user-supplied globs.\n\nDetection hints:\n- Search for `os/exec`, `exec.Command(`, `CommandContext(`, `\"sh\"`, `\"bash\"`, `\"-c\"`.\n- Trace untrusted input into command name/args.\n\nFix:\n- Use library APIs instead of subprocesses.\n- Hardcode command and allowlist/validate args.\n- If a shell is unavoidable, escape robustly and treat as high risk (prefer avoiding).\n\nNotes:\n- The Go `os/exec` package intentionally does invoke a shell; introducing `sh -c` reintroduces shell injection hazards.\n\n---\n\n### GO-SSRF-001: Prevent SSRF in outbound HTTP requests\nSeverity: Medium (High in cloud/LAN environments)\n\n- Note: For small stand alone projects this is less important. It is most important when deploying into an LAN or with other services listening on the same server.\n\nRequired:\n- MUST treat outbound requests to user-provided URLs as high risk.\n- SHOULD allowlist hosts/domains for any user-influenced URL fetch.\n- SHOULD block access to localhost/private IP ranges/link-local addresses and cloud metadata endpoints.\n- MUST restrict schemes to `http`/`https` (no `file:`, `gopher:`, etc.).\n- MUST set client timeouts and restrict redirects.\n\nInsecure patterns:\n- `http.Get(r.URL.Query().Get(\"url\"))`\n- “URL preview” / “webhook test” endpoints that fetch arbitrary URLs.\n\nDetection hints:\n- Search for `http.Get`, `client.Do`, and URL values derived from requests/DB.\n- Identify features that fetch remote resources.\n\nFix:\n- Parse URLs strictly; enforce scheme and allowlisted hostnames.\n- Resolve DNS and enforce IP-range restrictions (with care for DNS rebinding).\n- Set timeouts, disable redirects unless needed, and cap response sizes.\n\n---\n\n### GO-HTTPCLIENT-001: Outbound HTTP clients MUST set timeouts and close bodies\nSeverity: High (DoS and resource exhaustion)\n\nRequired:\n- MUST set an overall timeout on `http.Client` usage (or equivalent per-request deadlines via context + transport timeouts).\n- MUST ensure `resp.Body.Close()` is called for all successful requests (typically `defer resp.Body.Close()` immediately after error check).\n- SHOULD limit response body reads (do not `io.ReadAll` unbounded responses).\n- SHOULD restrict redirects for security-sensitive fetches (SSRF, auth flows).\n\nInsecure patterns:\n- Using `http.DefaultClient` / `http.Get` for user-influenced destinations with no timeout policy.\n- Missing `defer resp.Body.Close()` leading to resource leaks.\n- `io.ReadAll(resp.Body)` with no limit.\n\nDetection hints:\n- Search for `http.Get(`, `http.Post(`, `client := &http.Client{}` without `Timeout`, `client.Do(` and missing closes.\n- Search for `io.ReadAll(resp.Body)`.\n\nFix:\n- Use a configured client with timeouts.\n- Always close response bodies.\n- Use bounded readers (`io.LimitReader`) for large/untrusted responses.\n\nNotes:\n- The net/http package exposes `DefaultClient` as a zero-valued `http.Client`, which can easily lead to “no timeout” behavior unless configured.\n\n---\n\n### GO-REDIRECT-001: Prevent open redirects\nSeverity: Medium (can be High with auth flows)\n\nRequired:\n- MUST validate redirect targets derived from untrusted input (`next`, `redirect`, `return_to`).\n- SHOULD prefer only same-site relative paths.\n- SHOULD fall back to a safe default on validation failure.\n\nInsecure patterns:\n- `http.Redirect(w, r, r.URL.Query().Get(\"next\"), http.StatusFound)` with no validation.\n\nDetection hints:\n- Search for `http.Redirect(` and check origin of the location.\n\nFix:\n- Allowlist internal paths or known domains.\n- Reject absolute URLs unless explicitly needed and allowlisted.\n\n---\n\n### GO-CRYPTO-001: Cryptographic randomness MUST come from crypto/rand\nSeverity: High (Critical if used for auth/session tokens or keys)\n\nRequired:\n- MUST use `crypto/rand` for:\n  - session IDs, password reset tokens, API keys, CSRF tokens, nonces\n  - encryption keys, signing keys, salts when required\n- MUST NOT use `math/rand` for any security-sensitive value.\n- SHOULD use built-in helpers that produce appropriately strong tokens when available.\n\nInsecure patterns:\n- `math/rand.Seed(time.Now().UnixNano())` followed by token generation for auth or sessions.\n- Using UUIDv4-like constructs built from `math/rand`.\n\nDetection hints:\n- Search for `math/rand`, `rand.Seed`, `rand.Intn` in code that touches auth/session/token flows.\n- Search for custom token generators.\n\nFix:\n- Switch to `crypto/rand` (`rand.Reader`, `rand.Read`, or secure token helpers).\n- Ensure sufficient entropy and use URL-safe encoding.\n\nNotes:\n- The crypto/rand package provides secure randomness APIs and token generation helpers.\n\n---\n\n### GO-AUTH-001: Password storage MUST use adaptive hashing (bcrypt/argon2id) and safe comparisons\nSeverity: High\n\nRequired:\n- MUST hash passwords using an adaptive password hashing function (bcrypt or argon2id).\n- MUST NOT store plaintext passwords or reversible encryption of passwords.\n- MUST compare secrets in constant time when relevant (tokens, MACs, API keys) to reduce timing leaks.\n- SHOULD ensure password policies do not exceed algorithm constraints (e.g., bcrypt has input length limits; handle long passphrases appropriately).\n\nInsecure patterns:\n- `sha256(password)` stored as password hash.\n- Plaintext password storage.\n- Comparing secrets with `==` in timing-sensitive contexts.\n\nDetection hints:\n- Search for `sha1`, `sha256`, `md5` used on passwords.\n- Search for `bcrypt`/`argon2` usage; if absent, suspect.\n- Search for `==` comparisons on tokens/API keys.\n\nFix:\n- Use `bcrypt.GenerateFromPassword` / `CompareHashAndPassword` or argon2id with recommended parameters.\n- Use constant-time compare helpers when comparing MACs/tokens.\n\nNotes:\n- Go provides bcrypt in `golang.org/x/crypto/bcrypt`, and constant-time comparisons in `crypto/subtle`.\n\n---\n\n### GO-CONC-001: Data races and concurrency hazards MUST be treated as security-relevant\nSeverity: Medium to High (depends on what races affect)\n\nRequired:\n- MUST run tests with the race detector (`go test -race`) in CI for security-sensitive services.\n- MUST fix detected races; do not suppress without deep justification.\n- SHOULD treat shared mutable state in handlers as high risk; enforce synchronization or avoid shared mutability.\n\nInsecure patterns:\n- Global maps/slices mutated from multiple goroutines without a mutex.\n- Caches or auth/session state stored in globals without concurrency protection.\n- Racy access to authorization state (can lead to bypasses or inconsistent enforcement).\n\nDetection hints:\n- Search for `var someMap = map[...]...` used in handlers.\n- Look for missing `sync.Mutex`, `sync.Map`, channels, or other synchronization.\n- Ensure CI includes `-race` and that it runs relevant tests.\n\nFix:\n- Add proper synchronization or redesign to avoid shared mutable state.\n- Add race tests and run them continuously.\n\nNotes:\n- The Go race detector only finds races that occur in executed code paths; improve test coverage and run realistic workloads with `-race` where feasible.\n\n---\n\n### GO-UNSAFE-001: Use of unsafe/cgo MUST be minimized and audited like memory-unsafe code\nSeverity: High (Critical in high-risk code paths)\n\nRequired:\n- SHOULD avoid importing `unsafe` in application code unless absolutely necessary.\n- If `unsafe` is used, MUST treat it as “manual memory safety” requiring careful review and test coverage.\n- If `cgo` is used, MUST treat the C/C++ boundary as memory-unsafe; apply secure coding practices on the C side and isolate where possible.\n\nInsecure patterns:\n- Widespread `unsafe.Pointer` casts in parsing, serialization, auth, or network code.\n- `cgo` used for parsing or security boundaries without sandboxing.\n\nDetection hints:\n- Search for `import \"unsafe\"`, `unsafe.Pointer`, `// #cgo`, `import \"C\"`.\n- Prioritize review where unsafe touches untrusted input.\n\nFix:\n- Replace unsafe/cgo usage with safe standard library alternatives where possible.\n- Isolate unsafe code in small, well-tested modules with fuzz/race tests.\n\nNotes:\n- The unsafe package explicitly provides operations that step around Go’s type safety guarantees.\n\n--------------------------------------------------------------------\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\nToolchain & dependencies:\n- `FROM golang:` (Dockerfiles), `go-version:` (CI), `toolchain go` (go.mod), pinned old versions\n- `GOSUMDB=off`, `GOINSECURE`, `GONOSUMDB`, `GOPROXY=direct`\n- `replace` directives in `go.mod` to forks/paths\n- `govulncheck` missing in CI\n\nHTTP server hardening:\n- `http.ListenAndServe(`, `ListenAndServeTLS(`, `&http.Server{` with missing timeouts\n- `ReadHeaderTimeout: 0`, `ReadTimeout: 0`, `WriteTimeout: 0`, `IdleTimeout: 0`, missing `MaxHeaderBytes`\n\nBody parsing / DoS:\n- `io.ReadAll(r.Body)`, `json.NewDecoder(r.Body)` without size cap\n- `ParseMultipartForm`, `FormFile`, `multipart.NewReader` without explicit limits\n- Missing `http.MaxBytesReader`\n\nDebug exposure:\n- `import _ \"net/http/pprof\"`\n- `/debug/pprof`, `/debug/vars`\n\nTemplates / XSS / SSTI:\n- `text/template` used for HTML output\n- `template.HTML(`, `template.JS(`, `template.URL(` with user-controlled data\n- `.Parse(` on user-controlled strings\n\nFiles:\n- `http.ServeFile(` with user path\n- `http.FileServer(http.Dir(` pointing at repo root or uploads\n- `os.Open(filepath.Join(base, user))` without containment checks\n\nInjection:\n- SQL building with `fmt.Sprintf`, string concatenation near `db.Query/Exec`\n- `exec.Command(\"sh\",\"-c\", ...)`, `exec.Command(\"bash\",\"-c\", ...)`\n\nSSRF / outbound HTTP:\n- `http.Get(userURL)`, `client.Do(req)` where URL comes from request/DB\n- Missing client timeout, missing `resp.Body.Close()`, unbounded `io.ReadAll(resp.Body)`\n\nCrypto:\n- `math/rand` in token/session generation\n- `InsecureSkipVerify: true`\n- Password hashing with `sha256`/`md5` instead of bcrypt/argon2\n\nConcurrency:\n- Shared maps/slices mutated from handlers without locks\n- CI lacking `go test -race`\n\nAlways try to confirm:\n- data origin (untrusted vs trusted)\n- sink type (template/SQL/subprocess/files/http)\n- protective controls present (limits, validation, allowlists, middleware, network controls)\n\n--------------------------------------------------------------------\n\n## 6) Sources (accessed 2026-01-28)\n\nPrimary Go documentation:\n- Go Security Policy — https://go.dev/doc/security/policy\n- Go Release History (security fixes in patch releases) — https://go.dev/doc/devel/release\n- Go 1.25 Release Notes — https://go.dev/doc/go1.25\n- net/http (server timeouts, MaxHeaderBytes, DefaultClient) — https://pkg.go.dev/net/http\n- html/template (auto-escaping and trusted-template assumptions) — https://pkg.go.dev/html/template\n- crypto/tls (MinVersion defaults, InsecureSkipVerify warnings) — https://pkg.go.dev/crypto/tls\n- crypto/rand (secure randomness, token helpers) — https://pkg.go.dev/crypto/rand\n- crypto/subtle (constant-time comparisons) — https://pkg.go.dev/crypto/subtle\n- os/exec (no shell by default; command execution guidance) — https://pkg.go.dev/os/exec\n- unsafe (bypasses type safety) — https://go.dev/src/unsafe/unsafe.go\n- net/http/pprof (debug endpoints) — https://pkg.go.dev/net/http/pprof\n- cmd/go (module authentication via go.sum/checksum DB; env vars like GOINSECURE) — https://pkg.go.dev/cmd/go\n- Module Mirror and Checksum Database Launched (Go blog) — https://go.dev/blog/module-mirror-launch\n- govulncheck documentation — https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck\n- Go Race Detector documentation — https://go.dev/doc/articles/race_detector\n- bcrypt (password hashing) — https://pkg.go.dev/golang.org/x/crypto/bcrypt\n- Go vulnerability entry example (multipart resource consumption) — https://pkg.go.dev/vuln/GO-2023-1569\n\nOWASP Cheat Sheet Series (general web security):\n- Session Management — https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html\n- CSRF Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html\n- SSRF Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html\n- XSS Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html\n- HTTP Security Response Headers — https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html\n","core/skills/builtin/security-best-practices/references/javascript-express-web-server-security.md":"# Express (Node.js) Web Security Spec (Express 5.x / 4.19.2+, Node.js LTS)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new Express apps and routes.\n2. **Security review / vulnerability hunting** in existing Express code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session secrets, cookies, tokens).\n* MUST NOT “fix” security by disabling protections (e.g., weakening cookie flags, disabling CSRF defenses for cookie-authenticated apps, enabling permissive CORS, trusting proxy headers from the open internet, turning on debugging/stack traces in production, disabling TLS without a replacement).\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, middleware/config values, and runtime assumptions that justify the claim.\n* MUST treat uncertainty honestly: if a protection might exist in infrastructure (reverse proxy, gateway, WAF, CDN), report it as “not visible in app code; verify at runtime/config.”\n* MUST prefer vetted libraries and platform controls over “roll your own” crypto/auth/session/CSRF. Express explicitly expects the application to validate/handle user input correctly; it does not do this automatically. ([Express][1])\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new Express code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default APIs and proven libraries over custom security code.\n* MUST avoid introducing new risky sinks (shell execution, dynamic code evaluation, unsafe redirects, serving user files as HTML, template rendering from untrusted strings, unsafe filesystem paths, SSRF URL fetch endpoints, etc.).\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in an Express repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. Entrypoints (server/app bootstrap), deployment manifests, Dockerfiles, process manager config, CI/CD.\n2. Express settings + middleware stack order (helmet, parsers, auth, sessions, CSRF, CORS).\n3. Proxy trust (`trust proxy`) and IP/protocol/host handling. ([Express][2])\n4. Auth flows, sessions, cookies, password reset links, redirect handling. ([Express][1])\n5. State-changing routes + CSRF protections (cookie-authenticated apps). ([OWASP Cheat Sheet Series][3])\n6. Template rendering and XSS defenses (HTML generation, CSP, `res.locals`). ([OWASP Cheat Sheet Series][4])\n7. File handling (uploads + downloads + static files) and path traversal. ([Express][5])\n8. Injection classes (SQL, NoSQL, command execution, unsafe deserialization). ([OWASP Cheat Sheet Series][6])\n9. Outbound requests (SSRF) and webhook/callback delivery. ([OWASP Cheat Sheet Series][7])\n10. Rate limiting / brute-force defenses / abuse controls. ([Express][1])\n11. Dependency hygiene / lockfiles / npm audit / vulnerable Express versions. ([Express][1])\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nIn Express, common untrusted inputs include:\n\n* `req.params` (route parameters)\n* `req.query` (query string parameters; can be strings/arrays/objects depending on parsing) ([OWASP Cheat Sheet Series][8])\n* `req.body` from `express.json()`, `express.urlencoded()`, `express.text()`, `express.raw()` ([Express][5])\n* `req.headers` / `req.get(...)`\n* `req.cookies` / `req.signedCookies` (if cookie parsing middleware is used)\n* Upload metadata and filenames (e.g., multer `file.originalname`, `file.mimetype`)\n* Any data from external systems (webhooks, third-party APIs, message queues)\n* Any persisted user content (DB rows) that originated from users\n\nSpecial proxy note:\n\n* If `trust proxy` is enabled, values like `req.ip`, `req.hostname`, and `req.protocol` may be derived from `X-Forwarded-*` headers which **can be attacker-controlled** if your proxy chain is not correctly overwriting/removing them. ([Express][2])\n\n### 2.2 State-changing request\n\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook send), or initiate privileged actions.\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + function/route/middleware name + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common Express misconfigurations.\n\nMinimum baseline targets:\n\n* `helmet()` is used and configured (especially CSP where applicable), and fingerprinting is reduced (disable `x-powered-by`). ([Express][1])\n* A custom 404 handler and a custom error handler exist, and production does not leak internal stack traces. ([Express][1])\n* Cookie/session usage is deliberate:\n\n  * Not using default session cookie names\n  * Cookies use secure attributes (`Secure`, `HttpOnly`, `SameSite`) as appropriate\n  * Cookie-backed sessions never store secrets (they are readable by the client)\n  * Server-side sessions never use MemoryStore in production. ([Express][1])\n* Request body parsing has explicit limits (`express.json({ limit })`, `express.urlencoded({ limit, parameterLimit, depth })`). ([Express][5])\n* `trust proxy` is configured explicitly to match your proxy topology; not blindly `true`. ([Express][2])\n* Login/auth endpoints have brute-force protection and rate limiting. ([Express][1])\n* Dependencies are regularly audited/updated (`npm audit` + advisory response). ([Express][1])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### EXPRESS-INPUT-001: Treat all user input as untrusted and validate it\n\nSeverity: High\n\nRequired:\n\n* MUST validate and normalize untrusted inputs before using them in security-sensitive logic or dangerous sinks (DB queries, redirects, filesystem, HTML output, shell commands). Ensure the untrusted inputs are type checked and structure checked before using or passing forward.\n* SHOULD apply allowlists (known-good) rather than blocklists when feasible.\n* MUST reject or safely handle unexpected types/shapes in `req.query`, `req.params`, and `req.body`.\n\nInsecure patterns:\n\n* Passing `req.query`, `req.params`, `req.body` directly into database/query builders, redirects, filesystem paths, or templates.\n* Assuming `req.query.foo` is always a string (it can be an array/object depending on parsing). ([OWASP Cheat Sheet Series][8])\n\nDetection hints:\n\n* Identify “untrusted-to-sink” flows: request → sink (`res.redirect`, SQL execution, `sendFile`, `child_process`, template render, outbound fetch).\n* Search for direct usage of `req.query.*`, `req.body.*`, `req.params.*` in sensitive calls.\n\nFix:\n\n* Add schema validation (e.g., zod/joi/express-validator) at route boundaries.\n* Normalize types (e.g., force IDs to integers; reject arrays when scalar expected).\n\nNotes:\n\n* Express production security guidance explicitly says input validation/handling is the application’s responsibility. ([Express][1])\n\n---\n\n### EXPRESS-REDIRECT-001: Prevent open redirects; validate redirect targets\n\nSeverity: Medium\n\nRequired:\n\n* MUST validate redirect destinations derived from untrusted input (`next`, `return_to`, `url`).\n* SHOULD allowlist only same-site relative paths (preferred) or a strict allowlist of domains.\n* MUST fall back to a safe default when validation fails.\n\nInsecure patterns:\n\n* `res.redirect(req.query.next)` with no validation.\n* `res.redirect(req.body.url)` or `res.location(...)` using untrusted URLs.\n\nDetection hints:\n\n* Search for `res.redirect(` and `res.location(` and trace the source of the target.\n* Look for query params named `next`, `redirect`, `return`, `url`.\n\nFix:\n\n* Only allow relative paths (starting with `/`) and disallow `//`, backslashes, and encoded variants.\n* If cross-domain redirects are required, allowlist exact hosts and enforce `https`.\n\nNotes:\n\n* Express documentation calls out open redirects as dangerous user input and shows validating the host before redirecting. ([Express][1])\n* Keep Express updated: Express has had an open-redirect-related CVE affecting some versions, and upgrades are part of the mitigation posture. ([NVD][9])\n\n---\n\n### EXPRESS-HEADERS-001: Use Helmet (or equivalent) to set essential security headers\n\nSeverity: Medium\n\nRequired:\n\n* SHOULD use `helmet()` to set common security headers.\n* SHOULD configure CSP realistically (avoid `unsafe-inline` where possible) for pages that render user-influenced content.\n* SHOULD set `X-Content-Type-Options: nosniff`, clickjacking defenses (`X-Frame-Options` or CSP `frame-ancestors`), and appropriate referrer policy.\n\nNOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n\nInsecure patterns:\n\n* No security headers set in app code and no evidence they are set at the edge.\n* CSP missing on apps that display user content.\n* Misconfigured framing headers that unintentionally allow clickjacking.\n\nDetection hints:\n\n* Search for `helmet(` usage; check if CSP is configured or disabled.\n* Search for `res.setHeader(` / `res.set(` for security header setting.\n* If not visible in app code, check nginx/CDN config; otherwise flag “verify at edge.”\n\nFix:\n\n* Add `helmet()` early in middleware order and configure:\n\n  * CSP (`contentSecurityPolicy`)\n  * Frame protections (`frameguard` or CSP `frame-ancestors`)\n  * `X-Content-Type-Options` (`noSniff`)\n\nNotes:\n\n* Express production security best practices recommend Helmet and list headers Helmet sets by default. ([Express][1])\n* OWASP HTTP Headers guidance is a useful reference when tuning policies. ([OWASP Cheat Sheet Series][10])\n\n---\n\n### EXPRESS-FINGERPRINT-001: Reduce fingerprinting by disabling `x-powered-by` and customizing error/404 responses\n\nSeverity: Low (defense-in-depth)\n\nRequired:\n\n* SHOULD disable `X-Powered-By` using `app.disable('x-powered-by')`.\n* SHOULD provide a custom 404 handler and a custom error handler to avoid distinct default responses and to control information leakage.\n\nInsecure patterns:\n\n* Default `X-Powered-By: Express` header left enabled.\n* Default Express 404/error responses in production with identifiable formatting and/or stack traces.\n\nDetection hints:\n\n* Search for `app.disable('x-powered-by')`.\n* Check middleware tail for a custom 404 (`app.use((req,res)=>...)`) and a custom error handler (`app.use((err,req,res,next)=>...)`).\n* Check if `NODE_ENV` is correctly set for production behavior (see EXPRESS-ERROR-001). ([Express][11])\n\nFix:\n\n* Add:\n\n  * `app.disable('x-powered-by')`\n  * A custom 404 handler\n  * A custom error handler that logs server-side and returns generic messages client-side\n\nNotes:\n\n* Express docs explicitly recommend disabling `x-powered-by` and adding your own not-found and error handlers. ([Express][1])\n\n---\n\n### EXPRESS-COOKIE-001: Cookies must use secure attributes and minimal scope\n\nSeverity: Medium\n\nRequired:\n\n* MUST set cookie flags appropriately for any authentication/session cookie:\n\n  * `Secure` when HTTPS (production) IMPORTANT NOTE: Only set `Secure` in production environment if TLS is configured. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n  * `HttpOnly` for auth/session cookies\n  * `SameSite` set deliberately (`Lax` is a common baseline; `Strict` if compatible; `None` only with `Secure` and a justified cross-site need)\n* SHOULD avoid setting `domain` broadly (avoid “all subdomains” unless required).\n* SHOULD set bounded expiry appropriate to risk and UX.\n\nInsecure patterns:\n\n* Session/auth cookies without `HttpOnly`.\n* Cookies without `Secure` in production HTTPS.\n* `SameSite=None` + cookie-authenticated state-changing endpoints without CSRF protections.\n\nDetection hints:\n\n* Search for `res.cookie(`, `Set-Cookie`, `cookie: { ... }`, `express-session`, `cookie-session`.\n* Verify cookie flags in session middleware configuration.\n\nFix:\n\n* Set these attributes centrally in session/cookie middleware configuration.\n\nNotes:\n\n* Express production security guidance lists cookie security options (`secure`, `httpOnly`, etc.). ([Express][1])\n* `res.cookie()` ultimately sets `Set-Cookie` with options; defaults follow RFC 6265 behavior when options are omitted. ([Express][5])\n* OWASP session management guidance is relevant for choosing flags and lifetimes. ([OWASP Cheat Sheet Series][12])\n\n---\n\n### EXPRESS-SESS-001: Do not use the default session cookie name; avoid session fingerprinting\n\nSeverity: Low (defense-in-depth)\n\nRequired:\n\n* SHOULD override the default session cookie name (e.g., do not keep `connect.sid` when using `express-session`).\n* SHOULD use a generic name (e.g., `sessionId`) unless you have a compatibility reason.\n\nInsecure patterns:\n\n* `express-session` used with no `name:` configured (default cookie name).\n* Multiple apps on the same domain sharing a cookie name accidentally.\n\nDetection hints:\n\n* Search for `express-session` config blocks; check for `name:`.\n\nFix:\n\n* Set `name: 'sessionId'` (or similar) in `express-session` options.\n\nNotes:\n\n* Express docs explicitly recommend not using the default session cookie name to reduce fingerprinting. ([Express][1])\n\n---\n\n### EXPRESS-SESS-002: Session storage and lifecycle must be production-safe\n\nSeverity: High\n\nRequired:\n\n* MUST NOT use `MemoryStore` in production (it is not designed for production use).\n* MUST store session secrets outside source control and rotate them safely.\n* SHOULD regenerate sessions on login / privilege changes to reduce session fixation risk.\n* MUST NOT store sensitive secrets in client-readable cookie sessions.\n\nInsecure patterns:\n\n* `app.use(session({ store: new MemoryStore(), ... }))` or missing store (defaults to MemoryStore).\n* Hard-coded for example: `secret: 'keyboard cat'` / `secret: 's3Cur3'` in repo.\n* Using `cookie-session` to store access tokens, refresh tokens, or PII.\n\nDetection hints:\n\n* Search for `express-session` and look for `MemoryStore` usage or missing `store`.\n* Search for `secret:` in session config and check if it’s hard-coded.\n* Look for `req.session = ...` patterns and whether sensitive data is stored.\n\nFix:\n\n* Use a production session store (Redis, database-backed, etc.).\n* Load secrets from environment/secret manager.\n* On login: `req.session.regenerate(...)` or equivalent flow with safe privilege re-binding.\n\nNotes:\n\n* `express-session` explicitly warns that `MemoryStore` is not designed for production. ([Express][1])\n* `express-session` documents rotating secrets and session regeneration to guard against fixation. ([Express][1])\n* Express notes that cookie-backed sessions serialize data into the cookie and that cookie data is visible to the client; keep it small and non-secret. ([Express][1])\n\n---\n\n### EXPRESS-CSRF-001: Cookie-authenticated state-changing requests MUST be CSRF-protected\n\nSeverity: High\n\n- IMPORTANT NOTE: If cookies are not being used for auth (ie auth is via Authentication header or other passed token), then there is no CSRF risk.\n\nRequired:\n\n* MUST protect all state-changing endpoints (POST/PUT/PATCH/DELETE) that rely on cookies for authentication.\n* SHOULD use a well-understood CSRF mitigation (token-based is the typical baseline).\n* MAY add defense-in-depth: Origin/Referer validation, Fetch Metadata enforcement, SameSite cookies, custom header requirements for XHR/fetch—**but do not treat these as a full replacement** unless explicitly designed and justified.\n* MUST use at a minimum require a custom HTTP header if form based CRSF tokens are not practical, as this is the second strongest method.\n\nIMPORTANT NOTE:\n\n* If authentication is done via `Authorization: Bearer ...` headers (and not cookies), classic browser CSRF is typically not applicable;\n\nInsecure patterns:\n\n* Cookie-authenticated endpoints that change state with no CSRF protection.\n* Using GET for state-changing actions (amplifies CSRF risk).\n* “CSRF protection” that only checks a user-controlled field.\n\nDetection hints:\n\n* Enumerate routes with methods other than GET/HEAD and identify whether cookies gate auth.\n* Look for presence/absence of CSRF middleware and token checks.\n* Check JSON APIs too, not only HTML forms.\n\nFix:\n\n* Implement CSRF tokens for cookie-authenticated flows.\n* Add Origin/Referer checks where feasible, and ensure SameSite is set appropriately.\n\nNotes:\n\n* OWASP CSRF guidance and OWASP Node.js guidance both recommend anti-CSRF tokens as a standard control for web apps. ([OWASP Cheat Sheet Series][3])\n\n---\n\n### EXPRESS-CORS-001: CORS must be explicit and least-privilege\n\nSeverity: Medium (High if misconfigured with credentials)\n\nRequired:\n\n* If CORS is not needed, MUST keep it disabled.\n* If CORS is needed:\n\n  * MUST allowlist trusted origins (do not reflect arbitrary `Origin` without validation).\n  * MUST NOT combine broad origins with credentialed cookies (`Access-Control-Allow-Credentials: true`).\n  * SHOULD restrict methods, headers, and exposed headers to what’s required.\n\nInsecure patterns:\n\n* `Access-Control-Allow-Origin: *` with `Access-Control-Allow-Credentials: true`.\n* Reflecting `Origin` for all requests without allowlist validation.\n* Applying permissive CORS middleware globally when only a subset needs cross-origin access.\n\nDetection hints:\n\n* Search for `cors(`, `Access-Control-Allow-Origin`, `Access-Control-Allow-Credentials`.\n* Inspect whether cookies are used for auth on endpoints exposed cross-origin.\n\nFix:\n\n* Implement strict origin allowlist and ensure credentialed requests only for intended origins.\n* Consider splitting CORS config per route group rather than global.\n\nNotes:\n\n* OWASP HTTP header guidance covers security implications of response headers, including those that affect browser behavior; use it as a reference when reviewing header posture. ([OWASP Cheat Sheet Series][10])\n\n---\n\n### EXPRESS-PROXY-001: Reverse proxy trust (`trust proxy`) must be configured correctly\n\nSeverity: Medium (High if using IP based authentication)\n\nRequired:\n\n* If behind a reverse proxy/LB, MUST configure `app.set('trust proxy', ...)` to match the real proxy chain.\n* MUST NOT blindly set `trust proxy = true` unless you fully control the proxy behavior and header rewriting.\n* MUST ensure the last trusted proxy overwrites/removes `X-Forwarded-For`, `X-Forwarded-Host`, and `X-Forwarded-Proto` so clients cannot spoof them.\n\nInsecure patterns:\n\n* `app.set('trust proxy', true)` in an app directly exposed to the internet or behind unknown proxies.\n* Using `req.ip`, `req.protocol`, `req.hostname` for security decisions without correct proxy trust configuration.\n* Rate limiting keyed by `req.ip` with spoofable forwarded headers.\n\nDetection hints:\n\n* Search for `app.set('trust proxy'`.\n* Check infra docs (nginx/LB) for header rewriting behavior.\n* Identify any security logic using `req.ip`, `req.ips`, `req.protocol`, `req.hostname`.\n\nFix:\n\n* Set `trust proxy` to a hop count, explicit IP/subnet list, or a custom function matching your network.\n* Ensure proxies overwrite forwarded headers.\n\nNotes:\n\n* Express explicitly warns that when `trust proxy` is `true`, the client IP is derived from `X-Forwarded-For`, and if proxies don’t overwrite forwarded headers, the client can provide any value. It also describes that enabling trust proxy impacts `req.hostname` and `req.protocol` derived from forwarded headers. ([Express][2])\n\n---\n\n### EXPRESS-BODY-001: Request body size and parsing limits MUST be set appropriately\n\nSeverity: Low\n\nRequired:\n\n* SHOULD set explicit body size limits for:\n\n  * `express.json({ limit })`\n  * `express.urlencoded({ limit, parameterLimit, depth })`\n* SHOULD only enable the parsers you need; do not parse large bodies by default for all routes.\n* SHOULD enforce additional limits at the reverse proxy / gateway level.\n\nInsecure patterns:\n\n* No explicit body limits (accepting arbitrarily large JSON/urlencoded).\n* Global parsers applied to all routes when only some need bodies.\n* `parameterLimit` very high without justification (DoS potential).\n\nDetection hints:\n\n* Search for `express.json(` and confirm `limit` is set (or consciously accepted).\n* Search for `express.urlencoded(` and inspect `limit`, `parameterLimit`, and `depth`.\n* Review upload/webhook endpoints for special parsing needs.\n\nFix:\n\n* Configure parsers with conservative defaults and override per route group when needed.\n\nNotes:\n\n* Express documents `express.json` options (including `limit`, defaulting to 100kb) and explicitly notes `req.body` is untrusted and should be validated. ([Express][5])\n* Express documents `express.urlencoded` options including `limit`, `parameterLimit`, and `depth`. ([Express][5])\n* OWASP Node.js guidance also recommends setting request size limits. ([OWASP Cheat Sheet Series][8])\n\n---\n\n### EXPRESS-INPUT-002: Prevent HTTP Parameter Pollution and type confusion in `req.query`\n\nSeverity: Medium\n\nRequired:\n\n* MUST treat `req.query` values as potentially multi-valued (array/object), depending on query parsing.\n* SHOULD reject ambiguous multi-valued parameters for security-sensitive fields (e.g., `role`, `isAdmin`, `redirect`, `amount`, `userId`).\n* SHOULD consider explicit parsing or dedicated middleware if parameter pollution is a concern.\n\nInsecure patterns:\n\n* `if (req.query.admin) { ... }` without type checks (arrays/objects may coerce truthy).\n* Passing `req.query` directly into ORM/NoSQL query objects.\n\nDetection hints:\n\n* Search for security-sensitive comparisons on `req.query.*` without type enforcement.\n* Look for code that assumes query params are strings.\n\nFix:\n\n* Validate shape: enforce string-only for certain params and reject arrays/objects.\n* Normalize query parsing settings (simple vs extended) where applicable and documented.\n\nNotes:\n\n* OWASP Node.js cheat sheet explicitly highlights that Express query parsing can produce strings, arrays, or objects and recommends preventing HTTP Parameter Pollution. ([OWASP Cheat Sheet Series][8])\n\n---\n\n### EXPRESS-XSS-001: Prevent reflected/stored XSS in HTML responses and templating\n\nSeverity: High\n\nRequired:\n\n* MUST escape untrusted content in HTML output (templates should auto-escape by default; do not bypass).\n* MUST NOT inject untrusted strings into HTML without escaping/sanitization.\n* SHOULD set CSP (via Helmet) for apps rendering user-controlled content.\n* SHOULD keep `res.locals` free of user-controlled input intended for templates unless it is validated/escaped.\n\nInsecure patterns:\n\n* `res.send(\"<div>\" + req.query.q + \"</div>\")`\n* Passing untrusted HTML through “safe” template flags/filters.\n* Writing untrusted strings into `res.locals` and then rendering without escaping.\n\nDetection hints:\n\n* Search for `res.send(` with strings containing user input.\n* Search for template “safe” flags (engine-specific) and trace data origin.\n* Search for assignments to `res.locals` and whether they might contain untrusted data.\n\nFix:\n\n* Use a template engine with autoescaping; pass only validated data.\n* For rich text that must contain HTML, use a trusted sanitizer and an allowlist policy.\n* Add CSP with realistic directives.\n\nNotes:\n\n* Express API docs explicitly warn that `res.locals` “should not contain user-controlled input” and is often used to expose things like CSRF tokens to templates. ([Express][5])\n* OWASP XSS prevention guidance provides standard output-encoding and policy recommendations. ([OWASP Cheat Sheet Series][4])\n* Helmet can mitigate some XSS classes via headers such as CSP. ([Express][1])\n\n---\n\n### EXPRESS-TEMPLATE-001: Never render untrusted templates or template paths (SSTI / LFI risk)\n\nSeverity: Critical (if you can prove template strings/paths are user/attacker-controlled)\n\nRequired:\n\n* MUST NOT render templates whose contents or template path/name is influenced by untrusted input.\n* MUST NOT load templates from user-controlled filesystem locations.\n* SHOULD treat “email template editors”, “theme engines”, and “CMS-like template storage” as high-risk designs requiring sandboxing and isolation.\n\nInsecure patterns:\n\n* `res.render(req.query.view, data)` where `view` is not allowlisted.\n* Rendering a template from a string that includes user input (engine-specific).\n* Loading templates from uploads directories.\n\nDetection hints:\n\n* Search for `res.render(` where the first argument is derived from request/DB without allowlist.\n* Search for template compilation APIs (engine-specific) fed by user content.\n\nFix:\n\n* Use allowlisted template names and a fixed templates directory.\n* If user-defined templates are required, implement strict sandboxing and isolate execution.\n\nNotes:\n\n* Express’s template system depends on the chosen engine; assume unsafe if user input influences template selection or source.\n\n---\n\n### EXPRESS-FILES-001: Prevent path traversal and unsafe file serving (sendFile/download)\n\nSeverity: High\n\nRequired:\n\n* MUST NOT pass user-controlled filesystem paths directly to `res.sendFile()` / `res.download()` / filesystem APIs.\n* SHOULD use `res.sendFile` with a fixed `root` and strict options (e.g., deny dotfiles) when serving user-selected files from a directory.\n* MUST enforce authorization checks before serving user-specific files.\n\nInsecure patterns:\n\n* `res.sendFile(req.query.path)` or `res.download(req.params.file)` with no root restriction.\n* File-serving routes that accept `..` segments, encoded traversal, or absolute paths.\n\nDetection hints:\n\n* Search for `res.sendFile(` and trace the `path` argument origin.\n* Search for `res.download(` and trace the `path` argument origin.\n* Look for `fs.readFile`/`createReadStream` on paths derived from requests.\n\nFix:\n\n* Use an identifier-to-path mapping stored server-side (DB), not raw paths from clients.\n* Use `root: <trusted_base_dir>` and `dotfiles: 'deny'` where appropriate; validate the filename component strictly.\n\nNotes:\n\n* Express’s `res.sendFile` docs show using a `root` option and `dotfiles: 'deny'` as part of a safe serving configuration. ([Express][5])\n* `res.download` transfers the file as an attachment, but you still must control/validate the underlying `path`. ([Express][5])\n\n---\n\n### EXPRESS-STATIC-001: Harden `express.static` / serve-static and never serve untrusted uploads as active content\n\nSeverity: Medium (if serving untrusted user files if there are not robust limits tot eh file extensions)\n\nRequired:\n\n* MUST NOT serve user uploads from a public static directory as active content (especially HTML/JS/SVG) unless explicitly intended and sandboxed. If sure that the content is inactive (png, jpg, other images etc) then it may be safe. It may be good to validate image file extensions are allow-listed before serving them.\n* SHOULD configure static serving to:\n\n  * deny/ignore dotfiles\n  * avoid unintended directory indexes if not needed\n  * apply appropriate cache controls for immutable assets\n\nInsecure patterns:\n\n* `app.use(express.static('uploads'))` where users can upload arbitrary files.\n* Serving uploaded HTML or SVG inline from the same origin as the app.\n\nDetection hints:\n\n* Search for `express.static(` and identify served directories.\n* Compare served directories with upload storage locations.\n* Check for `dotfiles` and `index` options in static middleware.\n\nFix:\n\n* Store uploads outside any static web root and serve via controlled routes that set safe `Content-Type` and `Content-Disposition: attachment` when appropriate.\n* Configure `express.static(root, { dotfiles: 'deny'|'ignore', index: false (if desired) })`.\n\nNotes:\n\n* Express documents `express.static` options, including `dotfiles` behavior and `index`. ([Express][5])\n\n---\n\n### EXPRESS-UPLOAD-001: File uploads must be validated, stored safely, and served safely\n\nSeverity: Low - Medium\n\nRequired:\n\n* SHOULD enforce upload size limits (app + edge).\n* MUST validate file type using allowlists and content checks (not only filename extension).\n* MUST store uploads outside executable/static roots when possible.\n* SHOULD generate server-side filenames (random IDs); do not trust original names.\n* MUST serve potentially active formats safely (download attachment) unless explicitly intended.\n\nInsecure patterns:\n\n* Accepting arbitrary file types and serving them back inline.\n* Using `file.originalname` as the storage path.\n* Missing size/type validation.\n\nDetection hints:\n\n* Look for multer/busboy/formidable usage and check for `limits`.\n* Check where uploaded files are written and how they are served.\n* Check whether uploads end up under `public/` or any `express.static` root.\n\nFix:\n\n* Implement allowlist validation + safe storage + safe serving, per OWASP upload guidance.\n\nNotes:\n\n* OWASP File Upload guidance covers allowlists, content validation, storage, and safe serving patterns. ([OWASP Cheat Sheet Series][13])\n\n---\n\n### EXPRESS-INJECT-001: Prevent SQL injection (use parameterized queries / ORM)\n\nSeverity: High\n\nRequired:\n\n* MUST use parameterized queries or an ORM/query builder that parameterizes under the hood.\n* MUST NOT build SQL via string concatenation/template literals with untrusted input.\n\nInsecure patterns:\n\n* ``db.query(`SELECT * FROM users WHERE id = ${req.query.id}`)``\n* `\"SELECT ... WHERE name = '\" + req.body.name + \"'\"`\n\nDetection hints:\n\n* Grep for `SELECT`, `INSERT`, `UPDATE`, `DELETE` strings in JS/TS.\n* Trace untrusted input into `.query(...)`, `.execute(...)`, or raw SQL APIs.\n\nFix:\n\n* Replace with parameterized queries (placeholders) or ORM query APIs.\n* Validate types (e.g., integer IDs) before querying.\n\nNotes:\n\n* OWASP SQL injection prevention guidance strongly favors parameterized queries. ([OWASP Cheat Sheet Series][6])\n\n---\n\n### EXPRESS-INJECT-002: Prevent NoSQL injection / operator injection (Mongo-style)\n\nSeverity: High (app-dependent)\n\nRequired:\n\n* MUST validate types and schemas for any query object built from untrusted input.\n* MUST prevent operator injection (e.g., `$ne`, `$gt`, `$where`) if user input is merged into query objects.\n* SHOULD consider defensive libraries/middleware when appropriate.\n\nInsecure patterns:\n\n* `collection.find(req.body)` where the body is attacker-controlled.\n* Merging `req.query`/`req.body` into Mongo queries without schema validation.\n\nDetection hints:\n\n* Search for `find(`, `findOne(`, `aggregate(` calls where argument is request-derived.\n* Check for patterns like `{ ...req.query }` or `Object.assign(query, req.body)`.\n\nFix:\n\n* Use schema validation at boundary; explicitly construct query objects from validated fields only.\n\nNotes:\n\n* OWASP Node.js cheat sheet discusses input validation and mentions Node ecosystem modules commonly used for sanitization in NoSQL contexts. ([OWASP Cheat Sheet Series][8])\n\n---\n\n### EXPRESS-CMD-001: Prevent OS command injection (child_process)\n\nSeverity: Critical to High (depends on exposure), please prove it is user/attacker controlled\n\nRequired:\n\n* MUST avoid executing shell commands with untrusted input.\n* If subprocess is necessary:\n\n  * MUST avoid `exec()` / `execSync()` with attacker-influenced strings\n  * MUST NOT use `shell: true` with attacker-influenced data\n  * SHOULD use `spawn()` with an argument array and strict allowlists. Ensure the executable is hardcoded or allow-listed, do not use a user supplied command name.\n  * SHOULD place user-controlled values after `--` when supported by the subcommand to avoid flag injection\n\nInsecure patterns:\n\n* `exec(req.query.cmd)`\n* `exec(`convert ${userPath} ...`)`\n* `spawn('sh', ['-c', userString])`\n* `spawn(userString, ['foo'])`\n\nDetection hints:\n\n* Search for `child_process`, `exec(`, `execSync(`, `spawn(`, `fork(`.\n* Trace request/DB data into command construction.\n\nFix:\n\n* If possible, write the functionality in javascript or use a library instead of subprocess.\n* If unavoidable, hard-code command and strictly allowlist parameters.\n\nNotes:\n\n* OWASP OS command injection defense guidance covers avoid-shell and allowlist patterns. ([OWASP Cheat Sheet Series][14])\n\n---\n\n### EXPRESS-SSRF-001: Prevent server-side request forgery (SSRF) in outbound HTTP\n\nSeverity: Medium (High in cloud/LAN deployments)\n\nNOTE: This is mostly only applicable to apps which will be deployed in a cloud/LAN setup or have other http services on the same box. Sometimes the feature requires this functionality unavoidably (webhooks).\n\nRequired:\n\n* MUST treat outbound requests to user-provided URLs as high risk if there are other reachable private http endpoints.\n* SHOULD validate and restrict destinations (allowlist hosts/domains) for any user-influenced URL fetch.\n* SHOULD block access to:\n\n  * localhost / private IP ranges / link-local\n  * cloud metadata endpoints\n* MUST allow only `http`/`https` for URL fetch features (to avoid schemas such as `file:`,`javascript:`)\n* SHOULD set timeouts and restrict redirects.\n\nInsecure patterns:\n\n* `fetch(req.query.url)`\n* “URL preview” / “import from URL” endpoints that accept arbitrary URLs.\n\nDetection hints:\n\n* Search for `fetch(`, `axios(`, `got(`, `request(`, `node-fetch` usage where URL originates from users/DB.\n* Review webhook testers, previewers, image fetchers.\n\nFix:\n\n* Enforce scheme allowlist, host allowlist, DNS/IP resolution checks, timeouts, and redirect policy.\n* Consider network egress controls at infrastructure level.\n\nNotes:\n\n* OWASP SSRF prevention guidance provides standard controls and common pitfalls. ([OWASP Cheat Sheet Series][7])\n\n---\n\n### EXPRESS-ERROR-001: Error handling MUST not leak sensitive details in production\n\nSeverity: Low\n\nRequired:\n\n* SHOULD define a centralized error handler (`app.use((err, req, res, next) => ...)`) at the end of middleware.\n* MUST avoid returning stack traces, internal error messages, or secrets to clients in production.\n* SHOULD log errors server-side with appropriate redaction.\n* SHOULD ensure the app runs with production settings so default behavior doesn’t leak details.\n* MUST avoid logging or returning sensitive information such as secrets, env vars, sessions, cookies in error messages in production.\n\nInsecure patterns:\n\n* Returning `err.stack` to clients.\n* Using dev-only error middleware in production.\n* `NODE_ENV` left as development, causing verbose error responses.\n\nDetection hints:\n\n* Verify there is a final error-handling middleware.\n* Search for `res.status(500).send(err)` or similar.\n* Check production environment variables and startup scripts.\n\nFix:\n\n* Add a production-safe error handler that returns generic messages and logs details internally.\n* Ensure environment is configured for production behavior.\n\nNotes:\n\n* Express production security guidance recommends custom error handling. ([Express][1])\n* Express error handling docs describe the default error handler behavior and how production mode affects what is exposed. ([Express][11])\n\n---\n\n### EXPRESS-AUTH-001: Prevent brute-force attacks against authorization endpoints\n\nSeverity: Medium\n\nNOTE: This is highly application specific and while it is good to bring to the attention of the user, it is hard to fix without additional complex configurations. Prefer to inform the user and if they request you to help implement a solution, help walk them through possible solutions.\n\nRequired:\n\n* SHOULD protect login/auth endpoints against brute forcing.\n* SHOULD rate-limit by:\n\n  1. consecutive failed attempts per username+IP\n  2. failed attempts per IP over a time window\n\nInsecure patterns:\n\n* Unlimited login attempts.\n\nDetection hints:\n\n* Identify all auth endpoints and check for rate limiting/throttling.\n* Search for `rate-limiter-flexible`, `express-rate-limit`, or gateway policies.\n\nFix:\n\n* Implement rate-limiting/throttling (app or edge). Express docs point to `rate-limiter-flexible` as a tool for this approach. ([Express][1])\n\nNotes:\n\n* OWASP Node.js cheat sheet also recommends precautions against brute forcing. ([OWASP Cheat Sheet Series][8])\n\n---\n\n### EXPRESS-DEPS-001: Dependency and patch hygiene (Express + Node + critical middleware)\n\nSeverity: Medium / Low\n\nNOTE: `npm audit` often returns a large number of insignificant \"vulnerabilities\" which do not actually matter. You should only focus on Express or other extremely critical packages, ignoring ones listed in dev tools, bundlers, etc.\n\nDo not upgrade packages without concent from the user. This may break existing code in unexpected ways. Instead, inform them of the outdated packages.\n\nRequired:\n\n* MUST keep Express on a maintained version line (avoid EOL major versions).\n* MAY use `npm audit` in CI and during maintenance work.\n* SHOULD pin dependencies via lockfiles and review major updates carefully.\n\nInsecure patterns:\n\n* Running EOL Express versions (e.g., very old major lines).\n* Ignoring `npm audit` findings without triage.\n* Unpinned dependency ranges that auto-upgrade into insecure versions.\n\nDetection hints:\n\n* Check `package.json` and lockfiles for `express` version and other critical middleware versions.\n* Inspect CI pipelines for `npm audit`/SCA steps.\n\nFix:\n\n* Upgrade to latest stable Express and apply patches.\n* Add automated dependency scanning and upgrade process.\n\nNotes:\n\n* Express production security guidance emphasizes that dependency vulnerabilities can compromise the app, and recommends `npm audit`. ([Express][1])\n* Track security issues affecting Express versions (including known open-redirect-related CVEs). ([NVD][9])\n\n---\n\n### EXPRESS-DOS-001: Configure DoS protections (timeouts, limits, reverse proxy)\n\nSeverity: Low\n\nNOTE: It may be hard to tell from the provided application context if the application runs behind a reverse proxy. You can inform the user or recommend one, but do not attempt to configure one without them initiating it. This is highly deployment dependant.\n\nRequired:\n\n* SHOULD use a reverse proxy to provide caching, load balancing, and filtering controls when feasible.\n* MAY configure server/proxy timeouts and connection limits to reduce exposure to Slowloris and similar DoS patterns.\n* MUST ensure server/socket errors are handled so malformed connections do not crash the process. (Express should handle exceptions, but there are edgecases)\n\nInsecure patterns:\n\n* No reverse proxy in front of a public Node server, with defaults everywhere.\n* Missing error handlers on server/socket objects.\n* Extremely permissive timeouts and unlimited body sizes.\n\nDetection hints:\n\n* Inspect server creation (`http.createServer`, `https.createServer`) and whether timeouts are set.\n* Check proxy/gateway config for timeouts and max body size.\n\nFix:\n\n* Explain how to configure reverse proxy and timeouts, set request size limits\n* add robust error handling middleware\n\nNotes:\n\n* Node’s security guidance for HTTP DoS discusses using reverse proxies and correctly configuring server timeouts. ([Node.js][15])\n\n---\n\n### EXPRESS-NODE-INSPECT-001: Do not expose the Node inspector in production\n\nSeverity: Critical\n\nNOTE: Ensure that this detection is actually in the production path, and not just being used for local debugging.\n\nRequired:\n\n* MUST NOT run Node with `--inspect` (especially bound to non-loopback) in production.\n* MUST ensure `NODE_OPTIONS` or startup scripts do not enable inspector in prod.\n* SHOULD firewall/debug locally only.\n\nInsecure patterns:\n\n* `node --inspect=0.0.0.0:9229 app.js` in production.\n* Container/PM2/systemd configs enabling inspector.\n\nDetection hints:\n\n* Search for `--inspect` in Dockerfiles, Procfiles, systemd units, PM2 configs, npm scripts.\n* Check `NODE_OPTIONS`.\n\nFix:\n\n* Remove inspector flags from production start commands; restrict to local dev.\n\nNotes:\n\n* Node security guidance discusses inspector exposure risks (e.g., DNS rebinding) and recommends not running inspector in production. ([Node.js][15])\n\n---\n\n### EXPRESS-NODE-HTTP-001: Do not enable insecure HTTP parsing in production\n\nSeverity: High\n\nNOTE: Ensure that this detection is actually in the production path, and not just being used for local dev.\n\nRequired:\n\n* MUST NOT use Node’s `insecureHTTPParser` in production.\n* MAY suggest configuring front-end proxies to normalize ambiguous requests to reduce request smuggling risk.\n\nInsecure patterns:\n\n* Creating an HTTP server with `{ insecureHTTPParser: true }`.\n\nDetection hints:\n\n* Search for `insecureHTTPParser` in server creation code.\n\nFix:\n\n* Remove insecure parsing; rely on spec-compliant parsing and normalize at the edge.\n\nNotes:\n\n* Node security guidance explicitly recommends not using `insecureHTTPParser`. ([Node.js][15])\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning an Express repo, these patterns are high-signal:\n\n* TLS / transport:\n\n  * `app.listen(80` without reverse proxy mention; missing `helmet`; cookies missing `secure` ([Express][1]) (NOTE this only applies to web facing applications, internal apps likely won't have TLS)\n* Proxy trust:\n\n  * `app.set('trust proxy', true)`; logic using `req.ip`/`req.protocol`/`req.hostname` ([Express][2])\n* Security headers / fingerprinting:\n\n  * missing `helmet(`; missing `app.disable('x-powered-by')` ([Express][1])\n* Cookies / sessions:\n\n  * `express-session` with missing `store` (MemoryStore risk), hard-coded `secret:`, missing `cookie: { secure/httpOnly/sameSite }` ([Express][1])\n  * `cookie-session` storing large objects or secrets ([Express][1])\n* Body parsing limits:\n\n  * `express.json()` or `express.urlencoded()` without `limit`/`parameterLimit`/`depth` ([Express][5])\n* CSRF:\n\n  * POST/PUT/PATCH/DELETE routes using cookie auth with no CSRF tokens/origin checks ([OWASP Cheat Sheet Series][3])\n* Open redirects:\n\n  * `res.redirect(req.query.next)` or similar ([Express][1])\n* XSS / HTML output:\n\n  * `res.send(` building HTML with user input; template “safe” flags; untrusted values in `res.locals` ([Express][5])\n* File handling:\n\n  * `res.sendFile(` / `res.download(` where path originates from request; `express.static('uploads')` ([Express][5])\n* Injection:\n\n  * SQL strings + template literals into DB calls ([OWASP Cheat Sheet Series][6])\n  * `child_process.exec` / `execSync` / `shell: true` ([OWASP Cheat Sheet Series][14])\n* SSRF:\n\n  * outbound `fetch/axios/got` to user-provided URLs ([OWASP Cheat Sheet Series][7])\n* Brute force / abuse:\n\n  * auth endpoints lacking throttling; no rate limiting middleware ([Express][1])\n* Supply chain:\n\n  * outdated Express versions; no lockfiles; no `npm audit` workflow ([Express][1])\n* Node runtime hazards:\n\n  * `--inspect` in production scripts; `insecureHTTPParser` usage ([Node.js][15])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (HTML/template, SQL/NoSQL, subprocess, filesystem, redirect, outbound HTTP)\n* protective controls present (validation, allowlists, middleware, proxy config, header policies)\n* whether protections are at the edge vs in app code\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary Express documentation:\n\n* Express: Production Best Practices — Security: `https://expressjs.com/en/advanced/best-practice-security.html` ([Express][1])\n* Express: Behind Proxies (`trust proxy`): `https://expressjs.com/en/guide/behind-proxies.html` ([Express][2])\n* Express 5.x API Reference (parsers, static, sendFile, redirect, cookies): `https://expressjs.com/en/5x/api.html` ([Express][5])\n* Express: Error Handling: `https://expressjs.com/en/guide/error-handling.html` ([Express][11])\n\nSession middleware documentation:\n\n* express-session docs (cookie flags, secret rotation, fixation mitigation, MemoryStore warning): `https://expressjs.com/en/resources/middleware/session.html` ([Express][1])\n\nNode.js and npm official references:\n\n* Node.js — Security Best Practices (DoS, proxy guidance, inspector risks, request smuggling notes): `https://nodejs.org/en/learn/getting-started/security-best-practices` ([Node.js][15])\n* npm Docs — `npm audit`: `https://docs.npmjs.com/cli/v9/commands/npm-audit/` ([npm Docs][16])\n\nOWASP Cheat Sheet Series:\n\n* Session Management: `https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][12])\n* CSRF Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][3])\n* XSS Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][4])\n* Input Validation: `https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][17])\n* SQL Injection Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][6])\n* OS Command Injection Defense: `https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][14])\n* SSRF Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][7])\n* File Upload: `https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][13])\n* Unvalidated Redirects: `https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][18])\n* HTTP Headers: `https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][10])\n\nVersioning / advisories:\n\n* Express package version (npm): `https://www.npmjs.com/package/express`\n* Express open redirect advisory (CVE): `https://nvd.nist.gov/vuln/detail/CVE-2024-29041` ([NVD][9])\n\n[1]: https://expressjs.com/en/advanced/best-practice-security.html \"Security Best Practices for Express in Production\"\n[2]: https://expressjs.com/en/guide/behind-proxies.html \"Express behind proxies\"\n[3]: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html \"Cross-Site Request Forgery Prevention - OWASP Cheat Sheet Series\"\n[4]: https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html \"Cross Site Scripting Prevention - OWASP Cheat Sheet Series\"\n[5]: https://expressjs.com/en/5x/api.html \"Express 5.x - API Reference\"\n[6]: https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html \"SQL Injection Prevention - OWASP Cheat Sheet Series\"\n[7]: https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html \"Server Side Request Forgery Prevention - OWASP Cheat Sheet Series\"\n[8]: https://cheatsheetseries.owasp.org/cheatsheets/Nodejs_Security_Cheat_Sheet.html \"Nodejs Security - OWASP Cheat Sheet Series\"\n[9]: https://nvd.nist.gov/vuln/detail/cve-2024-29041?utm_source=chatgpt.com \"CVE-2024-29041 Detail - NVD\"\n[10]: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html \"HTTP Headers - OWASP Cheat Sheet Series\"\n[11]: https://expressjs.com/en/guide/error-handling.html \"Express error handling\"\n[12]: https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html \"Session Management - OWASP Cheat Sheet Series\"\n[13]: https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html \"File Upload - OWASP Cheat Sheet Series\"\n[14]: https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html \"OS Command Injection Defense - OWASP Cheat Sheet Series\"\n[15]: https://nodejs.org/en/learn/getting-started/security-best-practices \"Node.js — Security Best Practices\"\n[16]: https://docs.npmjs.com/cli/v9/commands/npm-audit/ \"npm-audit | npm Docs\"\n[17]: https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html \"Input Validation - OWASP Cheat Sheet Series\"\n[18]: https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html \"Unvalidated Redirects and Forwards - OWASP Cheat Sheet Series\"\n","core/skills/builtin/security-best-practices/references/javascript-general-web-frontend-security.md":"# Frontend JavaScript/TypeScript Web Security Spec (Vanilla Browser JS/TS, Modern Browsers)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new frontend JavaScript/TypeScript (no specific framework assumed).\n2. **Security review / vulnerability hunting** in existing frontend code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, hard-code, or commit secrets (API keys intended to be secret, private keys, passwords, OAuth refresh tokens, session tokens, cookies).\n  Notes:\n\n  * Frontend code is inherently observable by end users. If a value must remain secret, it must not be in browser-delivered code.\n  * If the project uses “public” keys (e.g., publishable analytics keys), they MUST be treated as non-secret and scoped accordingly.\n\n* MUST NOT “fix” security by disabling protections (e.g., weakening CSP with `unsafe-inline`/`unsafe-eval` without justification, removing origin checks for `postMessage`, switching to `innerHTML` for convenience, accepting arbitrary redirects/URLs, or turning off sanitization).\n\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and relevant HTML/CSP/config values that justify the claim.\n\n* MUST treat uncertainty honestly:\n\n  * Security headers (CSP, frame-ancestors, etc.) might be set by server/edge/CDN rather than in repo code. If not visible, report as “not visible here; verify at runtime/edge config.” (Also note that `<meta http-equiv=...>` only simulates a subset of headers; don’t assume other security headers exist just because a meta tag exists.) ([MDN Web Docs][1])\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new frontend JS/TS code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default browser APIs and proven libraries over custom security code (especially for HTML sanitization).\n* MUST avoid introducing new risky sinks (DOM XSS injection sinks like `innerHTML`, navigation to `javascript:` URLs, dynamic code execution via `eval`/`Function`, unsafe `postMessage`, unsafe third-party script loading, etc.). ([OWASP Cheat Sheet Series][2])\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a frontend repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. HTML entrypoints (`index.html`, server-rendered templates), script/style includes, and any CSP delivery (header vs meta). ([W3C][3])\n2. DOM XSS sinks (`innerHTML`, `document.write`, `insertAdjacentHTML`, event-handler attributes) and their data sources (URL params/hash, storage, postMessage, API responses). ([OWASP Cheat Sheet Series][2])\n3. Navigation/redirect handling (`window.location*`, link targets, URL allowlists) including `javascript:` URL hazards. ([MDN Web Docs][4])\n4. Cross-origin communication (`postMessage`, iframe embed patterns, sandboxing). ([MDN Web Docs][5])\n5. Storage of sensitive data (localStorage/sessionStorage) and assumptions about trust. ([OWASP Cheat Sheet Series][6])\n6. Third-party scripts / tag managers / CDNs, and integrity controls (SRI) and policy controls (CSP). ([OWASP Cheat Sheet Series][7])\n7. DOM clobbering gadgets and unsafe reliance on `window`/`document` named properties. ([OWASP Cheat Sheet Series][8])\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nExamples include:\n\n* URL-derived data: `location.href`, `location.search`, `location.hash`, `document.baseURI`, `new URLSearchParams(location.search)`, routing fragments. ([OWASP Cheat Sheet Series][2])\n* DOM content that may include user-controlled markup (comments, profiles, CMS content, markdown-to-HTML output, etc.), especially if inserted dynamically. ([OWASP Cheat Sheet Series][2])\n* `postMessage` event data (`event.data`) and metadata (`event.origin`) from other windows/frames. ([MDN Web Docs][5])\n* Browser storage: `localStorage`, `sessionStorage`, IndexedDB (contents can be attacker-influenced via XSS or local machine access; never treat as “trusted”). ([OWASP Cheat Sheet Series][6])\n* Any data returned from network calls (even if from “your API”), because it may contain stored attacker content that becomes dangerous only when inserted into the DOM. ([OWASP Cheat Sheet Series][2])\n\n### 2.2 Dangerous sink (DOM XSS / code execution sink)\n\nA sink is any API/operation that can execute script or interpret attacker-controlled strings as HTML/JS/URL in a security-sensitive way. High-signal sinks include:\n\n* HTML parsing / insertion: `innerHTML`, `outerHTML`, `insertAdjacentHTML`, `document.write`, `document.writeln`. ([OWASP Cheat Sheet Series][2])\n* Dynamic code execution: `eval`, `new Function`, `setTimeout(\"...\")`, `setInterval(\"...\")`. ([MDN Web Docs][10])\n* Navigation to script-bearing URLs (e.g., `javascript:`) via setters like `Location.href`/`window.location` (and via link `href` if attacker-controlled). ([MDN Web Docs][4])\n* Setting event handler attributes from strings, e.g. `setAttribute(\"onclick\", \"...\")`. ([OWASP Cheat Sheet Series][2])\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + function/class/module + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest baseline that prevents common frontend JS/TS security misconfigurations. Some items are “in repo” (HTML/JS) and some may live at the server/edge.\n\n### 3.1 Content Security Policy (CSP) baseline (SHOULD; MUST for high-risk apps)\n\n* SHOULD deliver CSP via HTTP response headers when possible.\n* MAY deliver CSP via an HTML `<meta http-equiv=\"Content-Security-Policy\" ...>` tag when you cannot set headers (e.g., purely static hosting constraints). ([MDN Web Docs][1])\n* If using CSP via `<meta http-equiv>`, MUST understand the limitations:\n\n  * The policy only applies to content that follows the meta element (so it must appear very early, before any scripts/resources you want governed). ([W3C][3])\n  * The following directives are **not supported** in a meta-delivered policy and will be ignored: `report-uri`, `frame-ancestors`, and `sandbox`. ([W3C][3])\n  * “Report-only” CSP cannot be set via a meta element. ([W3C][3])\n\nPractical baseline goals:\n\n* Avoid script sources `unsafe-inline` and `unsafe-eval` (they significantly weaken CSP’s value against XSS). ([MDN Web Docs][10])\n* Prefer nonce- or hash-based script policies if you need inline scripts. ([MDN Web Docs][10])\n* Consider enabling Trusted Types enforcement where feasible. ([MDN Web Docs][11])\n\n### 3.2 Third-party scripts baseline (SHOULD)\n\n* SHOULD minimize third-party script execution and treat it as equivalent privilege to first-party JS (it runs with your origin’s privileges). ([OWASP Cheat Sheet Series][7])\n* SHOULD use Subresource Integrity (SRI) for third-party scripts/styles loaded from CDNs. ([MDN Web Docs][12])\n\n### 3.3 Cross-window communication baseline (SHOULD)\n\n* SHOULD restrict `postMessage` communications to explicit origins, and validate both origin and message shape. ([MDN Web Docs][5])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### JS-XSS-001: Do not inject untrusted HTML into the DOM (avoid `innerHTML` and friends)\n\nSeverity: Critical if you can prove attacker-controlled input can reach these APIs; otherwise Medium\n\n\nRequired:\n\n* MUST treat `innerHTML`, `outerHTML`, and `insertAdjacentHTML` as dangerous sinks when their input can contain untrusted data. ([OWASP Cheat Sheet Series][2])\n* MUST prefer safe DOM APIs that do not parse HTML:\n\n  * `textContent` for text. ([OWASP Cheat Sheet Series][2])\n  * `document.createElement`, `appendChild`, `setAttribute` for non-event-handler attributes. ([OWASP Cheat Sheet Series][2])\n* If HTML insertion is truly required, SHOULD sanitize with a well-reviewed HTML sanitizer and strongly consider enforcing Trusted Types to confine usage to audited code paths. ([MDN Web Docs][11])\n\nInsecure patterns:\n\n* `el.innerHTML = userInput`\n* `el.insertAdjacentHTML('beforeend', userInput)`\n* `el.outerHTML = userInput`\n\nDetection hints:\n\n* Search for: `.innerHTML`, `.outerHTML`, `insertAdjacentHTML(`.\n* Trace the origin of inserted string: URL params/hash, postMessage, storage, API responses, DOM attributes. ([OWASP Cheat Sheet Series][2])\n\nFix:\n\n* Replace with `textContent` for plain text. ([OWASP Cheat Sheet Series][2])\n* For structured UI, build DOM nodes explicitly.\n* For “rich text” requirements:\n\n  * Sanitize using an allowlist-based sanitizer.\n  * Prefer returning safe “components” instead of arbitrary HTML strings.\n  * Use Trusted Types enforcement to ensure only `TrustedHTML` reaches sinks where supported. ([MDN Web Docs][11])\n\nMitigation:\n\n* Deploy a strict CSP and consider Trusted Types enforcement (`require-trusted-types-for 'script'`). ([MDN Web Docs][10])\n\nFalse positive notes:\n\n* If the string is provably constant or fully generated from trusted constants, it may be safe. Still prefer safer APIs.\n\n---\n\n### JS-XSS-002: Avoid `document.write` / `document.writeln` (XSS + document clobbering hazards)\n\nSeverity: Critical if you can prove attacker-controlled input can reach these APIs; otherwise Medium\n\nRequired:\n\n* MUST avoid `document.write()` and `document.writeln()` in production code (they are XSS vectors and can be abused with crafted HTML even if some browsers block injected `<script>` in certain situations). ([MDN Web Docs][13])\n* If legacy use is unavoidable, MUST ensure no untrusted input reaches these APIs and SHOULD enforce Trusted Types (`TrustedHTML`) where supported. ([MDN Web Docs][14])\n\nInsecure patterns:\n\n* `document.write(userInput)`\n* `document.writeln(getParam('q'))`\n\nDetection hints:\n\n* Search for `document.write(`, `document.writeln(`. ([OWASP Cheat Sheet Series][2])\n\nFix:\n\n* Replace with DOM manipulation (`createElement`, `appendChild`) or safe text insertion (`textContent`). ([OWASP Cheat Sheet Series][2])\n\nMitigation:\n\n* Strict CSP + Trusted Types enforcement reduces blast radius if a sink remains. ([MDN Web Docs][10])\n\n---\n\n### JS-XSS-003: Do not use string-to-code execution (`eval`, `new Function`, string timeouts)\n\nSeverity: Critical if you can prove attacker-controlled input can reach these APIs; otherwise Medium\n\nRequired:\n\n* MUST NOT pass untrusted data to:\n\n  * `eval()`\n  * `new Function(...)`\n  * `setTimeout(\"...\")` / `setInterval(\"...\")` with string arguments ([MDN Web Docs][10])\n* SHOULD avoid these APIs entirely in modern frontend code; refactor to non-eval logic. ([MDN Web Docs][10])\n* MUST NOT “fix CSP breakage” by adding `unsafe-eval` unless there is a documented, reviewed justification and compensating controls. ([MDN Web Docs][10])\n\nInsecure patterns:\n\n* `eval(userInput)`\n* `new Function(\"return \" + userInput)()`\n* `setTimeout(userInput, 0)` where userInput is a string\n\nDetection hints:\n\n* Search for `eval(`, `new Function`, `setTimeout(\"`, `setInterval(\"`.\n* Also search for construction of code strings used later.\n\nFix:\n\n* Replace dynamic code with:\n\n  * structured data + explicit branching/handlers,\n  * JSON parsing (`JSON.parse`) instead of `eval` for JSON. ([OWASP Cheat Sheet Series][2])\n\nMitigation:\n\n* CSP that blocks `eval()`-like APIs by default, and avoid `unsafe-eval`. ([MDN Web Docs][10])\n* Consider Trusted Types for controlled cases, but treat it as a hardening layer, not a license to keep eval patterns. ([MDN Web Docs][10])\n\n---\n\n### JS-XSS-004: Do not set event handler attributes from strings (e.g., `setAttribute(\"onclick\", \"...\")`)\n\nSeverity: High\n\nRequired:\n\n* MUST NOT use `setAttribute(\"on…\", string)` or similar patterns with untrusted data; this coerces strings into executable code in the event-handler context. ([OWASP Cheat Sheet Series][2])\n* SHOULD prefer `addEventListener` with function references.\n\nInsecure patterns:\n\n* `el.setAttribute(\"onclick\", userInput)`\n* `el.onclick = userControlledString` (string assignment)\n\nDetection hints:\n\n* Search for `.setAttribute(\"on`, `.onclick =`, `.onmouseover =`, etc.\n* Trace whether RHS can be influenced by URL/hash/storage/postMessage. ([OWASP Cheat Sheet Series][2])\n\nFix:\n\n* Replace with `addEventListener(\"click\", () => { ... })`.\n* If dynamic dispatch is needed, use an allowlisted mapping from identifiers to functions (no string eval). ([OWASP Cheat Sheet Series][2])\n\n---\n\n### JS-URL-001: Sanitize and allowlist URLs before navigation (especially `window.location` / `location.replace`)\n\nSeverity: Low (High if you can prove an attacker can fully control the URL)\n\nIMPORTANT: This can cause a lot of false positives. Please perform extra analysis to determine if the url is fully attacker controlled. If not fully attacker controlled, then this is informational at best.\n\nNOTE: It may be important functionality to be able to redirect to any given url. If that is the goal of the feature, then at a minimum, ensure it checks the schema even if the origin is allowed to be anything.\n\nRequired:\n\n* MUST treat any assignment to navigation targets as security-sensitive:\n\n  * `window.location = ...`\n  * `location.href = ...`\n  * `location.assign(...)`\n  * `location.replace(...)` ([MDN Web Docs][4])\n* MUST prevent navigation to `javascript:` URLs (and generally other script-bearing/active schemes), especially when input is derived from URL params, storage, or messages. ([MDN Web Docs][4]). Only allow `http:` and `https:`.\n* SHOULD validate/allowlist the destination. A safe baseline is:\n\n  * Allow only same-origin relative paths, OR\n  * Allow only a strict allowlist of origins and protocols (typically `https:` and optionally `http:` for localhost dev). ([OWASP Cheat Sheet Series][8])\n\nInsecure patterns:\n\n* `location.replace(getParam(\"next\"))`\n* `window.location = userSuppliedUrl`\n* `location.assign(window.redirectTo || \"/\")` where `redirectTo` can be clobbered or attacker-set ([OWASP Cheat Sheet Series][8])\n\nDetection hints:\n\n* Search for `window.location`, `location.href`, `location.assign`, `location.replace`.\n* Search for common redirect parameters: `next`, `returnTo`, `redirect`, `url`, `continue`.\n* Search for `javascript:` literal usage. ([MDN Web Docs][4])\n\nFix:\n\n* Parse and validate with `new URL(value, location.origin)` and then enforce:\n\n  * `url.protocol` in `{ \"https:\" }` (and only include `http:` in explicit dev-only code paths),\n  * `url.origin` equals `location.origin` for internal redirects, or in a strict allowlist for external redirects,\n  * optionally allow only specific path prefixes. ([MDN Web Docs][4])\n* If validation fails, navigate to a safe default (home/dashboard).\n\nMitigation:\n\n* Deploy strict CSP and Trusted Types enforcement to reduce the impact of DOM XSS sinks, but note that Trusted Types do not prevent every possible unsafe navigation scenario on their own. ([W3C][15])\n\nFalse positive notes:\n\nIMPORTANT: This can cause a lot of false positives. Please perform extra analysis to determine if the url is fully attacker controlled. If not fully attacker controlled, then this is informational at best.\n\n* Some apps intentionally support external redirects (SSO, payment flows). Those MUST be allowlisted and documented.\n\n---\n\n### JS-URL-002: Sanitize URLs before inserting into DOM URL contexts (`href`, `src`, etc.)\n\nSeverity: Low (High if you can prove an attacker can fully control the URL)\n\nIMPORTANT: This can cause a lot of false positives. Please perform extra analysis to determine if the url is fully attacker controlled. If not fully attacker controlled, then this is informational at best.\n\nRequired:\n\n* MUST treat setting URL-bearing DOM attributes/properties as security-sensitive, especially:\n\n  * `a.href`, `img.src`, `script.src`, `iframe.src`, `form.action`, `link.href`.\n* MUST prevent script-bearing schemes (`javascript:` and other active schemes) when values can be attacker-influenced. ([MDN Web Docs][4])\n* SHOULD prefer setting properties (e.g., `a.href = url.toString()`) after parsing and validation, rather than string concatenation.\n\nInsecure patterns:\n\n* `link.href = getParam(\"u\")`\n* `el.setAttribute(\"href\", userInput)` without validation\n* constructing URLs via concatenation with untrusted pieces\n\nDetection hints:\n\n* Search for `.href =`, `.src =`, `.action =`, `setAttribute(\"href\"`, `setAttribute(\"src\"`.\n* Search for `javascript:` / `data:` usage in URLs. ([MDN Web Docs][4])\n\nIMPORTANT: This can cause a lot of false positives. Please perform extra analysis to determine if the url is fully attacker controlled. If not fully attacker controlled, then this is informational at best.\n\nFix:\n\n* Use `new URL(...)` and validate:\n\n  * protocol allowlist\n  * avoid passing user-provided values into `<script src>` at all (treat as code execution). ([OWASP Cheat Sheet Series][8])\n\n---\n\n### JS-CSP-001: Use CSP; meta delivery is allowed\n\nSeverity: Medium to High (depends on threat model; High when handling untrusted content)\n\nNOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n\nRequired:\n\n* SHOULD deploy a CSP as a major defense-in-depth against XSS. ([MDN Web Docs][10])\n* MAY provide CSP via `<meta http-equiv=\"Content-Security-Policy\" ...>` when headers are not available. ([MDN Web Docs][1])\n* If CSP is delivered via meta, MUST:\n\n  * place it early (before scripts/resources you want governed), and\n  * not rely on unsupported directives in meta policies (`report-uri`, `frame-ancestors`, `sandbox`). ([W3C][3])\n* MUST avoid adding `unsafe-inline` as a “quick fix” for CSP issues unless explicitly required and reviewed (it defeats much of CSP’s purpose). ([MDN Web Docs][10])\n* MUST avoid adding `unsafe-eval` unless explicitly required and reviewed (it allows eval-like APIs that are commonly abused). ([MDN Web Docs][10])\n\nInsecure patterns:\n\n* No CSP present anywhere (repo HTML or server/edge) for an app that renders untrusted content.\n* CSP includes `script-src 'unsafe-inline'` and/or `script-src 'unsafe-eval'` without strong justification. ([MDN Web Docs][10])\n* CSP delivered via meta but includes `frame-ancestors` (it will be ignored in meta). ([W3C][3])\n\nDetection hints:\n\n* Search HTML for `<meta http-equiv=\"Content-Security-Policy\"`.\n* Search server/edge configs for `Content-Security-Policy` header.\n* If CSP is only in meta, check it appears before any `<script>` tags you want governed. ([W3C][3])\n\nFix:\n\n* Prefer header-delivered CSP at the server/edge.\n* If constrained to meta, keep a strong allowlist CSP and document the limitations; implement clickjacking protections (e.g., `frame-ancestors`) at the server/edge, not in meta. ([W3C][3])\n\n---\n\n### JS-CSP-002: Prefer strict CSP (nonces/hashes); avoid inline/eval patterns in code\n\nSeverity: Medium\n\nNOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n\nRequired:\n\n* SHOULD design frontend code to work under a strict CSP:\n\n  * avoid inline scripts and inline event handlers,\n  * avoid eval-like APIs (see JS-XSS-003),\n  * allow scripts via nonce or hash when needed. ([MDN Web Docs][10])\n\nInsecure patterns:\n\n* Large amounts of inline script blocks and inline `onclick=\"...\"` handlers.\n* Libraries that require `unsafe-eval`.\n\nDetection hints:\n\n* Search for `<script>` blocks with inline code, `onclick=\"`, `onload=\"`, etc.\n* Search for CSP directives containing `unsafe-inline` or `unsafe-eval`. ([MDN Web Docs][10])\n\nFix:\n\n* Move inline scripts into external JS files (same-origin).\n* Use nonces/hashes for any unavoidable inline blocks. ([MDN Web Docs][10])\n\n---\n\n### JS-TT-001: Use Trusted Types to reduce DOM XSS attack surface (where supported)\n\nSeverity: Low\n\nRequired:\n\n* SHOULD consider enabling Trusted Types enforcement with CSP `require-trusted-types-for 'script'` to make many DOM XSS sinks reject raw strings. ([MDN Web Docs][11])\n* If using Trusted Types, SHOULD also use the CSP `trusted-types` directive to restrict which policies can be created (reduces policy sprawl and improves auditability). ([MDN Web Docs][16])\n* MUST keep Trusted Types policy code small, heavily reviewed, and used as the only path to produce trusted values for sinks. ([W3C][15])\n\nInsecure patterns:\n\n* “Trusted Types enabled” but policy simply returns input unchanged (no sanitization/validation).\n* Many ad-hoc policies created across the codebase without restriction.\n* Belief that Trusted Types alone prevents all unsafe navigations or all XSS classes. (It targets DOM injection sinks; it is not a universal sandbox.) ([W3C][15])\n\nDetection hints:\n\n* Search for CSP directives: `require-trusted-types-for` and `trusted-types`.\n* Search code for `trustedTypes.createPolicy(` and inspect policy implementations. ([MDN Web Docs][11])\n\nFix:\n\n* Add a small set of well-reviewed policies (e.g., `createHTML` that sanitizes).\n* Restrict allowed policies via `trusted-types <policyName...>`.\n* Migrate sinks to require `TrustedHTML` / `TrustedScriptURL` as appropriate. ([MDN Web Docs][11])\n\n---\n\n### JS-MSG-001: `postMessage` must use strict origin validation and explicit targetOrigin\n\nSeverity: Medium (High if dangerous behavior can be triggered via postMessage)\n\nRequired:\n\n* When sending messages, MUST set an explicit `targetOrigin` (not `*`) to avoid sending data to an unexpected origin after redirects or window origin changes. ([MDN Web Docs][5])\n* When receiving messages, MUST:\n\n  * Validate `event.origin` exactly against an allowlist of expected origins (no substring matching). ([OWASP Cheat Sheet Series][6])\n  * Consider validating `event.source` (expected window reference) when applicable. ([MDN Web Docs][5])\n  * Validate `event.data` structure (schema/shape) and treat it purely as data (never evaluate it as code and never insert into DOM with `innerHTML`). ([OWASP Cheat Sheet Series][6])\n\nInsecure patterns:\n\n* `otherWindow.postMessage(payload, \"*\")`\n* `window.addEventListener(\"message\", (e) => { doSomething(e.data) })` with no `origin` check\n* `if (e.origin.includes(\"trusted.com\"))` (substring checks)\n* `el.innerHTML = e.data` ([OWASP Cheat Sheet Series][6])\n\nDetection hints:\n\n* Search for `postMessage(`, `addEventListener(\"message\"`, `onmessage =`.\n* Audit all handlers for explicit allowlist checks on `event.origin`. ([OWASP Cheat Sheet Series][6])\n\nFix:\n\n* Define an allowlist:\n\n  * `const ALLOWED = new Set([\"https://app.example.com\", \"https://accounts.example.com\"]);`\n  NOTE: For ease of development, you can use the current page's origin `window.location.origin` as a safe default origin.\n* On receive:\n\n  * `if (!ALLOWED.has(event.origin)) return;`\n  * Validate `event.data` with a strict schema and reject unknown/extra fields.\n* On send:\n\n  * use the exact expected origin string as `targetOrigin`. ([OWASP Cheat Sheet Series][6])\n\nMitigation:\n\n* Combine with a strict CSP and avoid DOM sinks in message paths. ([MDN Web Docs][10])\n\n---\n\n### JS-STORAGE-001: Web Storage is not a safe place for secrets (and is attacker-influencable)\n\nSeverity: Low\n\nRequired:\n\n* MUST NOT store sensitive secrets or session identifiers in `localStorage` (or `sessionStorage`) if compromise would matter; a single XSS can exfiltrate everything in storage. ([OWASP Cheat Sheet Series][6])\n* MUST treat values read from storage as untrusted input (attackers can load malicious values into storage via XSS). ([OWASP Cheat Sheet Series][6])\n* SHOULD prefer server-set cookies with `HttpOnly` for session identifiers (JS cannot set `HttpOnly`, so avoid storing session IDs in JS-accessible storage). ([OWASP Cheat Sheet Series][6])\n* SHOULD avoid hosting multiple unrelated apps on the same origin if they rely on storage separation (storage is origin-wide). ([OWASP Cheat Sheet Series][6])\n\nInsecure patterns:\n\n* `localStorage.setItem(\"access_token\", token)`\n* `localStorage.setItem(\"session\", sessionId)`\n* Assuming `localStorage` is “trusted because same-origin.”\n\nDetection hints:\n\n* Search for `localStorage.getItem`, `localStorage.setItem`, `sessionStorage.*`.\n* Flag storage keys named `token`, `jwt`, `session`, `auth`, `refresh`. ([OWASP Cheat Sheet Series][6])\n\nFix:\n\n* Use server-managed sessions or short-lived tokens delivered and rotated securely, with careful XSS defenses (CSP/Trusted Types) and minimal JS exposure.\n* If storage must be used for non-sensitive state, keep it non-auth and validate/escape before use.\n\n---\n\n### JS-SUPPLY-001: Third-party JavaScript is a major supply-chain risk; minimize and control it\n\nSeverity: Low\n\nRequired:\n\n* MUST treat third-party JS as equivalent to first-party JS in privilege (it can execute arbitrary code in your origin and access DOM data). ([OWASP Cheat Sheet Series][7])\n* SHOULD minimize third-party scripts and prefer:\n\n  * self-hosting / script mirroring,\n  * strict CSP allowlists,\n  * SRI for any CDN-hosted scripts,\n  * ongoing monitoring for unexpected changes. ([OWASP Cheat Sheet Series][7])\n\nInsecure patterns:\n\n* Loading arbitrary remote scripts from many vendors without review.\n* Using tag managers that can dynamically inject scripts with no integrity controls.\n* Allowing scripts from broad wildcards in CSP (e.g., `script-src *`). ([MDN Web Docs][10])\n\nDetection hints:\n\n* Search HTML for `<script src=\"https://...\">` and `tag manager` snippets.\n* Search CSP `script-src` sources for wildcards or overly broad domains.\n* Search for dynamic script injection: `document.createElement(\"script\")`, `script.src = ...`, `appendChild(script)`. ([OWASP Cheat Sheet Series][8])\n\nFix:\n\n* Remove unnecessary third-party tags.\n* Self-host or mirror scripts where possible.\n* Lock down CSP `script-src` to the smallest set of trusted sources.\n* Add SRI for CDN scripts/styles. ([OWASP Cheat Sheet Series][7])\n\n---\n\n### JS-SRI-001: Use Subresource Integrity (SRI) for third-party scripts/styles\n\nSeverity: Low\n\nRequired:\n\n* SHOULD use SRI to ensure browsers only load third-party resources if they match an expected cryptographic hash. ([MDN Web Docs][12])\n* MUST update SRI hashes whenever the underlying resource changes (pin versions; avoid “latest” URLs).\n\nInsecure patterns:\n\n* `<script src=\"https://cdn.example.com/lib.js\"></script>` with no `integrity`.\n* Loading `latest` or unpinned third-party resources.\n\nDetection hints:\n\n* Search for `<script src=\"https://` and `<link rel=\"stylesheet\" href=\"https://` without `integrity=`.\n* Check whether `integrity` is present and uses strong hashes (sha256/384/512 are typical). ([MDN Web Docs][12])\n\nFix:\n\n* Add `integrity=\"sha384-...\"` (or appropriate) and ensure proper CORS mode where needed.\n* Prefer self-hosting critical libraries.\n\n---\n\n### FS-DOMC-001: Prevent DOM clobbering (avoid relying on `window`/`document` named properties)\n\nSeverity: Medium to High (can become Critical if it enables script loading or `javascript:` navigation)\n\nRequired:\n\n* MUST NOT rely on implicit global variables or `window.someName` / `document.someName` lookups that can be clobbered by injected HTML elements with matching `id`/`name`. ([OWASP Cheat Sheet Series][8])\n* MUST avoid patterns like `let x = window.redirectTo || \"/safe\"; location.assign(x);` where `redirectTo` could be clobbered to an `<a>` element whose `href` is attacker-controlled (including `javascript:`). ([OWASP Cheat Sheet Series][8])\n* SHOULD use explicit variable declarations, local scope, and explicit DOM queries (`getElementById`) rather than named property access. ([OWASP Cheat Sheet Series][8])\n* If the app inserts user-controlled markup (even sanitized), SHOULD ensure sanitization strategies consider `id`/`name` collisions. ([OWASP Cheat Sheet Series][8])\n\nInsecure patterns:\n\n* `const cfg = window.config || {};` used for security-sensitive URLs.\n* `const redirect = window.redirectTo || \"/\"; location.assign(redirect);` ([OWASP Cheat Sheet Series][8])\n* Loading scripts from `window.*` config values without strict validation.\n\nDetection hints:\n\n* Search for `window.` and `document.` used as config stores (especially `||` fallback patterns).\n* Search for usage of `location.assign/replace` with variables that come from `window`/`document` properties.\n* Search for dynamic script creation (`createElement('script')`) where `.src` comes from a non-local variable. ([OWASP Cheat Sheet Series][8])\n\nFix:\n\n* Store config in module-scoped constants (not on `window`/`document`) and pass it explicitly.\n* Validate any URL-like config with protocol/origin allowlists (see FEJS-URL-001). ([OWASP Cheat Sheet Series][8])\n* Consider hardening: sanitization, CSP, and (in limited cases) freezing sensitive objects, but treat these as defense-in-depth, not a substitute for safe coding patterns. ([OWASP Cheat Sheet Series][8])\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* DOM XSS sinks:\n\n  * `.innerHTML`, `.outerHTML`, `insertAdjacentHTML(`\n  * `document.write(`, `document.writeln(` ([OWASP Cheat Sheet Series][2])\n\n* Dangerous navigation / URL sinks:\n\n  * `window.location`, `location.href`, `location.assign`, `location.replace`\n  * `javascript:` literals (and other suspicious schemes like `data:text/html`) ([MDN Web Docs][4])\n\n* String-to-code execution:\n\n  * `eval(`, `new Function`, `setTimeout(\"`, `setInterval(\"` ([MDN Web Docs][10])\n\n* Event-handler string injection:\n\n  * `.setAttribute(\"on`, `.onclick =`, `.onload =` with strings ([OWASP Cheat Sheet Series][2])\n\n* `postMessage`:\n\n  * `postMessage(` with `\"*\"` as targetOrigin\n  * `addEventListener(\"message\"` without strict `event.origin` allowlist checks ([MDN Web Docs][5])\n\n* Storage:\n\n  * `localStorage.setItem(` / `getItem(`, `sessionStorage.*`\n  * keys containing `token`, `jwt`, `session`, `auth`, `refresh` ([OWASP Cheat Sheet Series][6])\n\n* CSP and related:\n\n  * `Content-Security-Policy` header config (server/edge)\n  * `<meta http-equiv=\"Content-Security-Policy\" ...>`\n  * CSP containing `unsafe-inline` or `unsafe-eval`\n  * `require-trusted-types-for` / `trusted-types` directives ([MDN Web Docs][1])\n\n* Third-party scripts:\n\n  * `<script src=\"https://...\">` without `integrity=`\n  * Tag manager snippets and dynamic script injection code paths ([MDN Web Docs][12])\n\n\n* DOM clobbering gadgets:\n\n  * `window.<name> || ...` and `document.<name> || ...` patterns\n  * security-sensitive usage of `window`/`document` properties as config sources ([OWASP Cheat Sheet Series][8])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted),\n* sink type (HTML parse, navigation, code execution, message handling, storage),\n* protective controls present (CSP, Trusted Types, sanitizers, strict allowlists, schema validation).\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary standards / platform docs:\n\n* W3C Content Security Policy Level 2 (HTML `<meta>` delivery restrictions; unsupported directives in meta CSP): `https://www.w3.org/TR/CSP2/` ([W3C][3])\n* MDN: CSP Guide (strict CSP, nonces/hashes, `unsafe-inline`/`unsafe-eval`, eval blocking): `https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP` ([MDN Web Docs][10])\n* MDN: `<meta http-equiv>` (CSP via meta and warning about meta-based security headers): `https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/meta/http-equiv` ([MDN Web Docs][1])\n* MDN: `frame-ancestors` (and note it’s not supported in `<meta>`): `https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/frame-ancestors` ([MDN Web Docs][18])\n\nDOM XSS and dangerous sinks:\n\n* OWASP: DOM Based XSS Prevention Cheat Sheet (dangerous sinks + safe patterns like `textContent`): `https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][2])\n* MDN: `innerHTML` (security considerations): `https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML` ([MDN Web Docs][19])\n* MDN: `insertAdjacentHTML` (security considerations): `https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML` ([MDN Web Docs][20])\n* MDN: `document.write()` / `document.writeln()` (security considerations): `https://developer.mozilla.org/en-US/docs/Web/API/Document/write` and `https://developer.mozilla.org/en-US/docs/Web/API/Document/writeln` ([MDN Web Docs][13])\n\nURL scheme hazards:\n\n* MDN: `javascript:` URLs (execution on navigation; discouraged; references `window.location`): `https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Schemes/javascript` ([MDN Web Docs][4])\n\nTrusted Types:\n\n* W3C: Trusted Types spec (DOM XSS sinks include `Element.innerHTML` and `Location.href` setters; goals and limitations): `https://www.w3.org/TR/trusted-types/` ([W3C][15])\n* MDN: `require-trusted-types-for` directive: `https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/require-trusted-types-for` ([MDN Web Docs][11])\n* MDN: `trusted-types` directive: `https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/trusted-types` ([MDN Web Docs][16])\n\nCross-window messaging:\n\n* MDN: `window.postMessage` (security guidance: specify targetOrigin; validate origin): `https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage` ([MDN Web Docs][5])\n* OWASP: HTML5 Security Cheat Sheet (Web Messaging guidance: explicit origin, strict checks, no `innerHTML`): `https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][6])\n\nThird-party scripts and integrity:\n\n* OWASP: Third Party JavaScript Management Cheat Sheet (risks and mitigations including SRI/mirroring): `https://cheatsheetseries.owasp.org/cheatsheets/Third_Party_Javascript_Management_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][7])\n* MDN: Subresource Integrity overview: `https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity` ([MDN Web Docs][12])\n* W3C: Subresource Integrity spec: `https://www.w3.org/TR/sri-2/` ([W3C][21])\n\nDOM clobbering:\n\n* OWASP: DOM Clobbering Prevention Cheat Sheet (named property access risk; example attacks involving `location.assign` and `javascript:`): `https://cheatsheetseries.owasp.org/cheatsheets/DOM_Clobbering_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][8])\n\n[1]: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/meta/http-equiv \"https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/meta/http-equiv\"\n[2]: https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html\"\n[3]: https://www.w3.org/TR/CSP2/ \"Content Security Policy Level 2\"\n[4]: https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Schemes/javascript \"javascript: URLs - URIs | MDN\"\n[5]: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage \"https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage\"\n[6]: https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html\"\n[7]: https://cheatsheetseries.owasp.org/cheatsheets/Third_Party_Javascript_Management_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Third_Party_Javascript_Management_Cheat_Sheet.html\"\n[8]: https://cheatsheetseries.owasp.org/cheatsheets/DOM_Clobbering_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/DOM_Clobbering_Prevention_Cheat_Sheet.html\"\n[9]: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/noopener \"https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/noopener\"\n[10]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP \"https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP\"\n[11]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/require-trusted-types-for \"https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/require-trusted-types-for\"\n[12]: https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity \"https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity\"\n[13]: https://developer.mozilla.org/en-US/docs/Web/API/Document/write \"https://developer.mozilla.org/en-US/docs/Web/API/Document/write\"\n[14]: https://developer.mozilla.org/en-US/docs/Web/API/Document/writeln \"https://developer.mozilla.org/en-US/docs/Web/API/Document/writeln\"\n[15]: https://www.w3.org/TR/trusted-types/ \"https://www.w3.org/TR/trusted-types/\"\n[16]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/trusted-types \"https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/trusted-types\"\n[18]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/frame-ancestors \"https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/frame-ancestors\"\n[19]: https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML \"https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML\"\n[20]: https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML \"https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML\"\n[21]: https://www.w3.org/TR/sri-2/ \"https://www.w3.org/TR/sri-2/\"\n","core/skills/builtin/security-best-practices/references/javascript-jquery-web-frontend-security.md":"# jQuery Frontend Security Spec (jQuery 4.0.x, modern browsers)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new jQuery-based frontend code.\n2. **Security review / vulnerability hunting** in existing jQuery-based code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session tokens, refresh tokens, CSRF tokens, session cookies).\n* MUST treat the browser as an attacker-controlled environment:\n\n  * Frontend checks (UI gating, “disable button”, hidden fields, client-side validation) MUST NOT be treated as authorization or a security boundary.\n  * Server-side authorization and validation MUST exist even if frontend is “correct”.\n* MUST NOT “fix” security by disabling protections (e.g., relaxing CSP to allow `unsafe-inline`, enabling JSONP “because it works”, adding broad CORS, disabling sanitization, suppressing security checks).\n* MUST provide evidence-based findings during audits: cite file paths, code snippets, and relevant configuration values.\n* MUST treat uncertainty honestly: if a protection might exist at the edge (CDN/WAF/reverse proxy headers like CSP), report it as “not visible in repo; verify at runtime/config”.\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new jQuery code or modify existing jQuery code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default patterns: text insertion, DOM node construction, allowlists, and proven sanitization libraries over custom escaping.\n* MUST avoid introducing new risky sinks (HTML string building, dynamic script loading, JSONP, inline script/event-handler attributes, unsafe URL assignment, unsafe object merging).\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a repo that uses jQuery (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in the structured format (see §2.3).\n\nRecommended audit order:\n\n1. jQuery sourcing, versions, and dependency hygiene (script tags, lockfiles, CDN usage, SRI).\n2. CSP / Trusted Types / security headers posture (in repo and at runtime if observable).\n3. DOM XSS: untrusted sources → jQuery sinks (`.html`, `.append`, `$(\"<…>\")`, `.load`, etc.).\n4. Script execution sinks: JSONP, `dataType:\"script\"`, `$.getScript`, dynamic `<script>` insertion.\n5. URL/attribute assignment (`href`, `src`, `style`, `on*` attributes).\n6. Prototype pollution / unsafe object merging (`$.extend` patterns).\n7. AJAX auth patterns + CSRF for cookie-based sessions.\n8. Third-party plugins and untrusted content rendering paths (comments, WYSIWYG, markdown-to-HTML).\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nExamples include:\n\n* Any data from the server that originates from users (user profiles, comments, “display name”, rich text, filenames).\n* Data from third-party APIs or services.\n* Browser-controlled sources:\n\n  * `location.href`, `location.search`, `location.hash`\n  * `document.URL`, `document.baseURI`, `document.referrer`\n  * `window.name`\n  * `localStorage` / `sessionStorage`\n  * `postMessage` event data (unless strict origin and schema validation exists)\n  * Any DOM content that could have been injected previously (stored XSS)\n\n### 2.2 High-risk “sinks” in jQuery contexts\n\nA sink is a code path where untrusted input can become interpreted as executable code or HTML.\n\nKey jQuery sink categories:\n\n* HTML insertion / parsing:\n\n  * DOM manipulation methods that accept HTML strings such as `.html()`, `.append()`, and related methods (see CVE notes below). ([NVD][1])\n  * `$(htmlString)` (when the argument can be interpreted as HTML markup).\n  * `jQuery.parseHTML(html, …, keepScripts)` especially with `keepScripts=true`. ([jQuery API][2])\n  * `.load(url)` (loads HTML into DOM; has special script execution behavior). ([jQuery API][3])\n* Script execution / dynamic code loading:\n\n  * `$.getScript()` / `$.ajax({ dataType: \"script\" })` (executes fetched JavaScript). ([jQuery API][4])\n  * JSONP (`dataType: \"jsonp\"` or implicit JSONP behavior) (executes remote JavaScript as a response). ([jQuery API][5])\n  * `eval`, `new Function`, `setTimeout(\"…\")`, `setInterval(\"…\")`, `$.globalEval` (if present)\n* Dangerous attribute assignment:\n\n  * Assigning untrusted strings to `href`, `src`, `srcdoc`, `style`, or event-handler attributes (`onload`, `onclick`, etc.)\n  * `javascript:` URLs are particularly dangerous and discouraged. ([MDN Web Docs][6])\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + function/component + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common jQuery-related security failures.\n\n### 3.1 Use a supported, patched jQuery version (MUST)\n\n* MUST use a supported jQuery major version and keep it updated.\n* As of 2026-01-27, the jQuery project ships jQuery 4.0.0 as the latest major release. ([blog.jquery.com][7])\n* If you must support very old browsers (notably IE < 11), jQuery 4 does not support them and you may need to stay on jQuery 3.x; treat this as a higher risk posture and patch aggressively. ([blog.jquery.com][7])\n\n### 3.2 Load jQuery safely (MUST)\n\n* MUST load jQuery only from:\n\n  * Your own build pipeline (bundled via npm/yarn + lockfile), or\n  * The official jQuery CDN / a trusted CDN with Subresource Integrity (SRI) enabled.\n* If loading from a CDN, SHOULD use SRI (`integrity`) and correct `crossorigin` settings; the jQuery project explicitly supports and recommends SRI on its CDN. (Retrieved from [jquery.com][8])\n\n### 3.3 CSP + Trusted Types (SHOULD, and MUST where available/required by policy)\n\n* SHOULD deploy a Content Security Policy (CSP) that reduces XSS impact (especially `script-src` restrictions and avoiding `unsafe-inline`). If not done through HTTP server, this can be done through the `<meta http-equiv=\"Content-Security-Policy\" content=\"...\">` tag. ([OWASP Cheat Sheet Series][9]) NOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n* SHOULD consider Trusted Types as a strong defense-in-depth against DOM XSS. ([W3C][10])\n* If you deploy the CSP directive `require-trusted-types-for`, then code MUST route DOM-injection through Trusted Types policies. ([MDN Web Docs][11])\n* Note: jQuery 4.0 explicitly added Trusted Types support so that TrustedHTML can be used with jQuery manipulation methods without violating `require-trusted-types-for`. ([blog.jquery.com][7])\n\n### 3.4 Security headers and cookie posture (defense in depth; SHOULD)\n\nEven though these are typically set server-side, they materially reduce the blast radius of jQuery-related mistakes. However if the context is only the frontend web application, these cannot be acted on.\n\n* SHOULD set common security headers (CSP, `X-Content-Type-Options: nosniff`, clickjacking protection via `frame-ancestors` / `X-Frame-Options`, `Referrer-Policy`). ([OWASP Cheat Sheet Series][12])\n* SHOULD avoid storing long-lived secrets/tokens in places accessible to JavaScript (like `localStorage`) unless the threat model explicitly accepts “XSS == account takeover”. This is not jQuery-specific, but jQuery-heavy DOM manipulation increases the chance of DOM XSS regressions; reduce the payoff.\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### JQ-SUPPLY-001: jQuery MUST be patched; do not run known vulnerable versions\n\nSeverity: Medium (High if internet-facing app AND version is known-vulnerable)\n\nNOTE: Before performing an upgrade, get concent from the user and try to understand if they have reasons to keep it back. Upgrading can break applications in unexpected ways. Report and recommend upgrades rather than just performing them.\n\nRequired:\n\n* MUST NOT use jQuery versions with known high-impact vulnerabilities when a patched version exists.\n* MUST upgrade past:\n\n  * CVE-2019-11358 (prototype pollution in jQuery before 3.4.0). ([NVD][13])\n  * CVE-2020-11022 / CVE-2020-11023 (XSS risks in DOM manipulation methods when handling untrusted HTML; patched in 3.5.0). ([NVD][1])\n\nInsecure patterns:\n\n* Script tags or package manifests referencing old jQuery (e.g., `jquery-1.*`, `jquery-2.*`, `jquery-3.3.*`, `jquery-3.4.*`, `jquery-3.4.1`, etc.).\n* Bundled vendor directories containing old minified jQuery without an upgrade path.\n\nDetection hints:\n\n* Search HTML/templates for `jquery-` and parse version strings.\n* Check `package.json`, `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`.\n* Check `vendor/`, `public/`, `static/`, `assets/`, `wwwroot/` for `jquery*.js`.\n\nFix:\n\n* Upgrade to current jQuery (prefer latest stable major; as of 2026-01-27, 4.0.0 is current). ([blog.jquery.com][7])\n* If upgrade is constrained, at minimum upgrade beyond the CVE thresholds and add compensating controls (strong CSP, strict sanitization, remove risky APIs like JSONP, remove deep-extend of untrusted objects).\n\nNotes:\n\n* If a product requirement forces old versions, report as “accepted risk requiring compensating controls”.\n\n---\n\n### JQ-SUPPLY-002: Third-party script loading SHOULD use integrity and trusted origins\n\nSeverity: High\n\nRequired:\n\n* MUST load jQuery and plugins only from trusted origins.\n* If loaded from CDN, SHOULD use SRI (`integrity`) and correct `crossorigin` handling. ([jquery.com][8])\n\nInsecure patterns:\n\n* `<script src=\"https://…/jquery.min.js\"></script>` with no `integrity`.\n* Loading jQuery from random third-party CDNs without an explicit trust decision.\n\nDetection hints:\n\n* Scan HTML for `<script src=` and check for `integrity=` + `crossorigin=`.\n* Identify dynamic script insertion with untrusted URLs (see JQ-EXEC-001).\n\nFix:\n\n* Prefer bundling via npm + lockfile.\n* If using CDN, copy official script tag (jQuery CDN supports SRI). ([jquery.com][8])\n\nNote: If unable to get the correct SRI tag, skip this step but tell the user. If you end up using the wrong one the app will not function. In that case remove it and inform the user.\n\n---\n\n### JQ-XSS-001: Untrusted data MUST NOT be inserted as HTML via jQuery DOM-manipulation methods\n\nSeverity: High (if attacker-controlled content reaches these sinks)\n\nRequired:\n\n* MUST treat any HTML string insertion as a code execution boundary.\n* MUST use safe alternatives for untrusted text:\n\n  * `.text(untrusted)` (text, not HTML). ([jQuery API][14])\n  * `.val(untrusted)` for form fields. ([jQuery API][15])\n  * Create elements and set text/attributes safely instead of concatenating HTML strings.\n\nInsecure patterns (examples):\n\n* `$(selector).html(untrusted)`\n* `$(selector).append(untrusted)`\n* `$(selector).before(untrusted)` / `.after(untrusted)` / `.replaceWith(untrusted)` / `.wrap(untrusted)` (and similar)\n* Building markup: `\"<div>\" + untrusted + \"</div>\"` then passing to jQuery\n\nDetection hints:\n\n* Grep for: `.html(`, `.append(`, `.prepend(`, `.before(`, `.after(`, `.replaceWith(`, `.wrap(`, `.wrapAll(`, `.wrapInner(`\n* Trace dataflow into these calls from sources in §2.1.\n\nFix:\n\n* Replace with `.text()` / `.val()` or node construction:\n\n  * `const $el = $(\"<span>\").text(untrusted); container.append($el);`\n* If the output must contain limited markup, see JQ-XSS-002 (sanitization).\n\nNotes:\n\n* Older jQuery versions had additional edge cases even when attempting sanitization; patched in 3.5.0+. Still: never rely on “string sanitization” alone—prefer structured creation or proven sanitizers. ([GitHub][16])\n\n---\n\n### JQ-XSS-002: If rendering user-controlled HTML is required, it MUST be sanitized with a proven HTML sanitizer\n\nSeverity: Medium (High if rich HTML is attacker-controlled and sanitizer is weak/misconfigured)\n\nRequired:\n\n* MUST NOT “roll your own” HTML sanitizer with regexes.\n* If user-controlled HTML must be displayed (e.g., rich text comments), MUST sanitize using a well-maintained HTML sanitizer and a restrictive allowlist.\n\n  * DOMPurify is a common choice; use conservative configuration and keep it updated. ([GitHub][17])\n  * Where available, MAY consider the browser HTML Sanitizer API (note: limited browser availability). ([MDN Web Docs][18])\n* SHOULD pair sanitization with CSP and, where feasible, Trusted Types for defense in depth. ([OWASP Cheat Sheet Series][9])\n\nInsecure patterns:\n\n* Regex-based “strip `<script>`” or “escape `<`” attempts followed by `.html()` insertion.\n* DOMPurify (or similar) configured to allow overly broad tags/attributes, or configuration that’s not reviewed.\n\nDetection hints:\n\n* Search for “sanitize” helper functions, regex replacing `<`/`>` patterns, or “allow all tags” configs.\n* Identify features that render user-generated “rich text” or “custom HTML”.\n* Check if sanitizer results are inserted with `.html()` or equivalent sinks.\n\nFix:\n\n* Introduce a sanitizer with strict allowlist.\n* Centralize the “sanitize then inject” pattern into a single reviewed module.\n* Add regression tests covering representative malicious inputs (don’t store payloads in logs or telemetry).\n\nFalse positive notes:\n\n* If content is guaranteed trusted (e.g., compiled templates shipped by you), document the trust boundary and why it is not attacker-controlled.\n\n---\n\n### JQ-XSS-003: `$(untrustedString)` and `jQuery.parseHTML` MUST NOT process attacker-controlled markup\n\nSeverity: High (if attacker-controlled)\n\nRequired:\n\n* MUST NOT pass attacker-controlled strings to `$()` when they might be interpreted as HTML.\n* MUST treat `jQuery.parseHTML(html, …, keepScripts)` as a high-risk primitive; keepScripts MUST be `false` for any untrusted input. ([jQuery API][2])\n\nInsecure patterns:\n\n* `const $node = $(untrusted);`\n* `$.parseHTML(untrusted, /* context */, true)` (scripts preserved)\n\nDetection hints:\n\n* Search for `$(` calls where the argument is not a static selector or static markup.\n* Search for `$.parseHTML(` and inspect the `keepScripts` argument.\n\nFix:\n\n* Use DOM creation with constant tag names and `.text()` for untrusted values.\n* If parsing HTML is necessary, sanitize first (JQ-XSS-002) and keep scripts disabled.\n\n---\n\n### JQ-XSS-004: `.load()` MUST be treated as an HTML+script injection surface\n\nSeverity: Medium (High if URL/content is attacker-controlled)\n\nRequired:\n\n* MUST NOT use `.load()` with attacker-controlled URLs or attacker-controlled HTML fragments.\n* MUST understand jQuery `.load()` script behavior:\n\n  * Without a selector in the URL, content is passed to `.html()` before scripts are removed, which can execute scripts. ([jQuery API][3])\n* SHOULD prefer `fetch()`/XHR to retrieve data, then render with safe DOM creation or sanitize explicitly.\n\nInsecure patterns:\n\n* `$(\"#target\").load(untrustedUrl)`\n* `$(\"#target\").load(\"/path?param=\" + untrusted)`\n\nDetection hints:\n\n* Search for `.load(` across JS/TS files.\n* Identify whether a selector is appended to the URL (the behavior differs). ([jQuery API][3])\n* Trace whether the URL can be influenced by user input.\n\nFix:\n\n* Replace `.load()` with:\n\n  * `fetch()` to retrieve JSON, then render via `.text()` / node construction, or\n  * `fetch()` to retrieve HTML, sanitize it, then inject.\n* If `.load()` must remain, ensure the URL is constant or strictly allowlisted and the returned content is trusted.\n\n---\n\n### JQ-EXEC-001: Dynamic script execution and script fetching MUST NOT be reachable from untrusted input\n\nSeverity: High\n\nRequired:\n\n* MUST NOT fetch-and-execute scripts from untrusted or user-influenced URLs.\n* MUST treat these as code execution primitives:\n\n  * `$.getScript(url)` executes the fetched script in the global context. ([jQuery API][4])\n  * `$.ajax({ dataType: \"script\" })` and other script-typed requests that execute responses.\n* SHOULD remove these patterns unless there is a strong, reviewed justification.\n\nInsecure patterns:\n\n* `$.getScript(untrustedUrl)`\n* `$.ajax({ url: untrustedUrl, dataType: \"script\" })`\n* Dynamic `<script src=...>` injection where `src` is derived from untrusted input.\n\nDetection hints:\n\n* Search for `getScript(`, `dataType: \"script\"`, `globalEval`, `eval`, `new Function`.\n* Look for “plugin loader” or “theme loader” features that accept URLs.\n\nFix:\n\n* Bundle scripts at build time.\n* If runtime-loading is required, restrict to allowlisted, versioned, integrity-checked assets (and ideally still avoid runtime code loading).\n\n---\n\n### JQ-AJAX-001: JSONP MUST be disabled unless the endpoint is fully trusted (and even then, avoid)\n\nSeverity: Medium (High if attacker can influence URL/endpoint)\n\nRequired:\n\n* MUST NOT use JSONP for untrusted endpoints because it executes JavaScript responses.\n* When using `$.ajax`, MUST explicitly disable JSONP for non-fully-trusted targets; jQuery’s own docs recommend setting `jsonp: false` “for security reasons” if you don’t trust the target. ([jQuery API][5])\n* SHOULD prefer CORS with JSON (`dataType: \"json\"`) and explicit origin allowlists server-side.\n\nInsecure patterns:\n\n* `dataType: \"jsonp\"`\n* URLs containing `callback=?` or patterns that trigger JSONP behavior. callback arguments are historically XSS vectors.\n* `$.get(untrustedUrl)` without pinning `dataType` and disabling JSONP (risk depends on options and jQuery behavior)\n\nDetection hints:\n\n* Search for `jsonp`, `dataType: \"jsonp\"`, `callback=?`.\n* Search for cross-domain AJAX where the URL is not hard-coded or allowlisted.\n\nFix:\n\n* Use JSON over HTTPS with CORS configured server-side.\n* Set:\n\n  * `dataType: \"json\"`\n  * `jsonp: false` (defense in depth when URL might be ambiguous) ([jQuery API][5])\n\n---\n\n### JQ-AJAX-002: State-changing AJAX requests using cookie auth MUST be CSRF-protected\n\nSeverity: High\n\nNOTE: This only matters when using cookie based auth. If the request use Authorization header, there is no CSRF potential.\n\nRequired:\n\n* If authentication uses cookies, MUST protect state-changing requests (POST/PUT/PATCH/DELETE) against CSRF.\n* SHOULD use server-verified CSRF tokens; for AJAX calls, tokens are commonly sent in a custom header. ([OWASP Cheat Sheet Series][19])\n* MUST NOT treat “it’s an AJAX request” as CSRF protection by itself.\n\nInsecure patterns:\n\n* `$.post(\"/transfer\", {...})` or `$.ajax({ method: \"POST\", ... })` with cookie auth and no CSRF token/header.\n* “CSRF protection” that only checks for `X-Requested-With` (defense-in-depth only, not primary).\n\nDetection hints:\n\n* Enumerate state-changing AJAX calls and locate whether they include CSRF tokens.\n* Identify how the server expects CSRF validation (meta tag, cookie-to-header double submit, synchronizer token, etc.).\n\nFix:\n\n* Add CSRF token inclusion in a centralized place, e.g., `$.ajaxSetup({ headers: { \"X-CSRF-Token\": token } })`, and ensure server verifies.\n* Follow OWASP CSRF guidance for token properties and validation. ([OWASP Cheat Sheet Series][19])\n\nFalse positive notes:\n\n* If auth is not cookie-based (e.g., Authorization header bearer token) CSRF risk is different; verify actual auth mechanism.\n\n---\n\n### JQ-ATTR-001: Untrusted values MUST NOT be written into dangerous attributes without validation/allowlisting\n\nSeverity: Low (High for events like onclick)\n\nRequired:\n\n* MUST validate/allowlist URLs written into `href`, `src`, `action`, etc.\n* MUST block dangerous schemes; `javascript:` URLs are discouraged because they can execute code. ([MDN Web Docs][6])\n* MUST NOT set event-handler attributes (`onclick`, `onerror`, etc.) from strings.\n* SHOULD avoid writing untrusted strings into `style` attributes; prefer toggling predefined CSS classes.\n\nInsecure patterns:\n\n* `$(\"a\").attr(\"href\", untrustedUrl)`\n* `$(\"img\").attr(\"src\", untrustedUrl)`\n* `$(el).attr(\"style\", untrustedCss)`\n* `$(el).attr(\"onclick\", untrustedJs)`\n\nDetection hints:\n\n* Search for `.attr(\"href\"`, `.attr(\"src\"`, `.attr(\"style\"`, `.prop(\"href\"`, `.prop(\"src\"`.\n* Trace whether inputs come from URL params, server JSON, DOM, or storage.\n\nFix:\n\n* Parse and validate URLs with `new URL(value, location.origin)` and allowlist protocols (`https:` etc.) and hostnames when needed.\n* For navigation targets, prefer relative paths you construct rather than full URLs.\n* Replace `style` strings with `addClass/removeClass` using predefined class names.\n\n---\n\n### JQ-SELECTOR-001: User-controlled selector fragments MUST be escaped with `jQuery.escapeSelector`\n\nSeverity: Medium (can become High if it enables wrong-element selection in security-relevant UI)\n\nRequired:\n\n* If you must select by an ID/class that can contain special CSS characters, SHOULD use `jQuery.escapeSelector()` (available in jQuery 3.0+). ([jQuery API][20])\n* MUST NOT concatenate raw attacker-controlled strings into selector expressions.\n\nInsecure patterns:\n\n* `$(\"#\" + untrustedId)`\n* `$(\"[data-id='\" + untrusted + \"']\")` (especially without strict quoting/escaping)\n\nDetection hints:\n\n* Search for `\"#\" +`, `\". \" +`, or template strings used inside `$(` selectors.\n* Look for “select by user-supplied id”.\n\nFix:\n\n* `$(\"#\" + $.escapeSelector(untrustedId))` ([jQuery API][20])\n* Prefer stable internal IDs over user-derived selectors.\n\nNotes:\n\n* This is often “robustness”, but it can become security-relevant if incorrect selection causes UI to reveal/modify the wrong data or skip security-related prompts.\n\n---\n\n### JQ-PROTOTYPE-001: Do not deep-merge untrusted objects; prevent prototype pollution\n\nSeverity: Medium\n\nRequired:\n\n* MUST NOT deep-merge (`$.extend(true, …)`) attacker-controlled objects into application objects without filtering dangerous keys.\n* MUST ensure jQuery is >= 3.4.0 to avoid CVE-2019-11358 prototype pollution behavior. ([NVD][13])\n\nInsecure patterns:\n\n* `$.extend(true, target, untrustedObj)`\n* `$.extend(true, {}, defaults, untrustedObj)` where untrustedObj comes from URL/JSON/storage\n\nDetection hints:\n\n* Search for `$.extend(true` and inspect sources of merged objects.\n* Search for “merge options” / “apply config” patterns using untrusted JSON.\n\nFix:\n\n* Prefer:\n\n  * Shallow merges with an allowlisted set of keys, or\n  * A safe merge helper that explicitly rejects `__proto__`, `prototype`, `constructor`, and nested occurrences.\n* Keep jQuery patched.\n\n---\n\n### JQ-CSP-001: CSP and Trusted Types SHOULD be used to make DOM XSS harder to introduce and exploit\n\nSeverity: Medium\n\nRequired:\n\n* SHOULD deploy CSP as defense-in-depth against XSS. ([OWASP Cheat Sheet Series][9])\n* If enabling Trusted Types (`require-trusted-types-for`), MUST ensure DOM injection goes through Trusted Types policies. ([MDN Web Docs][11])\n* When using jQuery 4, SHOULD take advantage of its Trusted Types support (TrustedHTML inputs). ([blog.jquery.com][7])\n\nInsecure patterns:\n\n* “Fixing” a jQuery feature by weakening CSP (`script-src 'unsafe-inline'` / `'unsafe-eval'`) without a compensating plan.\n* No CSP on applications that render user content or manipulate DOM heavily.\n\nDetection hints:\n\n* Look for CSP headers (server configs, framework middleware, meta tags).\n* If not visible in repo, flag as “verify at edge/runtime”.\n\nFix:\n\n* Add CSP incrementally; start by eliminating inline scripts and inline event handlers, then tighten `script-src`.\n* Add Trusted Types where supported and feasible.\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* jQuery version / sourcing:\n\n  * `jquery-*.js` in `vendor/` or `static/`\n  * `package.json` dependency `jquery` pinned to old versions\n  * CDN script tags lacking `integrity`/`crossorigin` ([jquery.com][8])\n* HTML injection sinks (DOM XSS):\n\n  * `.html(`, `.append(`, `.prepend(`, `.before(`, `.after(`, `.replaceWith(`, `.wrap(`\n  * `$(` where argument might be HTML / template strings\n  * `$.parseHTML(` especially with `keepScripts=true` ([jQuery API][2])\n  * `.load(` (and whether selector is appended; script behavior differs) ([jQuery API][3])\n* Script execution / dynamic code:\n\n  * `$.getScript(`, `dataType: \"script\"` ([jQuery API][4])\n  * `dataType: \"jsonp\"` or `jsonp:` usage; `callback=?` patterns ([jQuery API][5])\n  * `eval`, `new Function`, `setTimeout(\"…\")`, `$.globalEval`\n* Dangerous attribute writes:\n\n  * `.attr(\"href\", …)`, `.attr(\"src\", …)`, `.attr(\"style\", …)`\n  * Any assignment of `javascript:`-like schemes or suspicious URL construction ([MDN Web Docs][6])\n* Selector construction:\n\n  * `$(\"#\" + user)` and similar; fix via `$.escapeSelector` ([jQuery API][20])\n* Prototype pollution:\n\n  * `$.extend(true, …, userObj)`; ensure jQuery >= 3.4.0 and filter dangerous keys ([NVD][13])\n* CSRF posture for AJAX:\n\n  * `$.post(` / `$.ajax({ method: ... })` with cookies and no CSRF token/header ([OWASP Cheat Sheet Series][19])\n* Defense-in-depth:\n\n  * Absence of CSP/security headers in configs (or not visible; require runtime verification) ([OWASP Cheat Sheet Series][12])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (HTML insertion / script execution / attribute / selector / object merge)\n* protective controls present (sanitizer, allowlists, CSP, Trusted Types, CSRF validation)\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary jQuery project documentation and release notes:\n\n* jQuery 4.0.0 release notes (Trusted Types/CSP changes; version info): `https://blog.jquery.com/2026/01/17/jquery-4-0-0/`. ([blog.jquery.com][7])\n* Download jQuery (latest version info; CDN + SRI guidance): `https://jquery.com/download/`. ([jquery.com][8])\n* jQuery API: `.html()`: `https://api.jquery.com/html/`. ([jQuery API][21])\n* jQuery API: `.text()`: `https://api.jquery.com/text/`. ([jQuery API][14])\n* jQuery API: `.append()`: `https://api.jquery.com/append/`. ([jQuery API][22])\n* jQuery API: `.load()` (script execution behavior): `https://api.jquery.com/load/`. ([jQuery API][3])\n* jQuery API: `jQuery.parseHTML(…, keepScripts)`: `https://api.jquery.com/jQuery.parseHTML/`. ([jQuery API][2])\n* jQuery API: `$.ajax()` (`jsonp: false` security note): `https://api.jquery.com/jQuery.ajax/`. ([jQuery API][5])\n* jQuery API: `$.getScript()` (executes script): `https://api.jquery.com/jQuery.getScript/`. ([jQuery API][4])\n* jQuery API: `jQuery.escapeSelector()`: `https://api.jquery.com/jQuery.escapeSelector/`. ([jQuery API][20])\n\njQuery vulnerabilities / advisories:\n\n* NVD CVE-2019-11358 (prototype pollution; jQuery < 3.4.0): `https://nvd.nist.gov/vuln/detail/CVE-2019-11358`. ([NVD][13])\n* NVD CVE-2020-11022 (XSS risk in DOM manipulation methods; patched in 3.5.0): `https://nvd.nist.gov/vuln/detail/CVE-2020-11022`. ([NVD][1])\n* NVD CVE-2020-11023 (XSS risk involving `<option>`; patched in 3.5.0): `https://nvd.nist.gov/vuln/detail/CVE-2020-11023`. ([NVD][23])\n* GitHub Security Advisory GHSA-gxr4-xjj5-5px2 (jQuery htmlPrefilter XSS; patched in 3.5.0): `https://github.com/jquery/jquery/security/advisories/GHSA-gxr4-xjj5-5px2`. ([GitHub][16])\n\nOWASP Cheat Sheet Series (web app security foundations relevant to jQuery usage):\n\n* XSS Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html`. ([OWASP Cheat Sheet Series][24])\n* DOM-based XSS Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html`. ([OWASP Cheat Sheet Series][25])\n* CSRF Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html`. ([OWASP Cheat Sheet Series][19])\n* HTTP Security Headers: `https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html`. ([OWASP Cheat Sheet Series][12])\n* Content Security Policy Cheat Sheet: `https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html`. ([OWASP Cheat Sheet Series][9])\n\nBrowser/platform references (SRI, CSP, Trusted Types, and dangerous URL schemes):\n\n* MDN: Subresource Integrity (SRI): `https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity`. ([MDN Web Docs][26])\n* W3C: SRI specification: `https://www.w3.org/TR/sri-2/`. ([W3C][27])\n* MDN: CSP guide: `https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP`. ([MDN Web Docs][28])\n* MDN: `require-trusted-types-for` directive: `https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/require-trusted-types-for`. ([MDN Web Docs][11])\n* MDN: Trusted Types API: `https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API`. ([MDN Web Docs][29])\n* W3C: Trusted Types specification: `https://www.w3.org/TR/trusted-types/`. ([W3C][10])\n* MDN: `javascript:` URL scheme warning: `https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Schemes/javascript`. ([MDN Web Docs][6])\n* DOMPurify project documentation: `https://github.com/cure53/DOMPurify`. ([GitHub][17])\n\n[1]: https://nvd.nist.gov/vuln/detail/cve-2020-11022?utm_source=chatgpt.com \"CVE-2020-11022 Detail - NVD\"\n[2]: https://api.jquery.com/jQuery.parseHTML/?utm_source=chatgpt.com \"jQuery.parseHTML()\"\n[3]: https://api.jquery.com/load/?utm_source=chatgpt.com \".load() | jQuery API Documentation\"\n[4]: https://api.jquery.com/jQuery.getScript/?utm_source=chatgpt.com \"jQuery.getScript()\"\n[5]: https://api.jquery.com/jQuery.ajax/?utm_source=chatgpt.com \"jQuery.ajax()\"\n[6]: https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Schemes/javascript?utm_source=chatgpt.com \"javascript: URLs - URIs - MDN Web Docs\"\n[7]: https://blog.jquery.com/2026/01/17/jquery-4-0-0/ \"jQuery 4.0.0 | Official jQuery Blog\"\n[8]: https://jquery.com/download/ \"Download jQuery | jQuery\"\n[9]: https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html?utm_source=chatgpt.com \"Content Security Policy - OWASP Cheat Sheet Series\"\n[10]: https://www.w3.org/TR/trusted-types/?utm_source=chatgpt.com \"Trusted Types\"\n[11]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/require-trusted-types-for?utm_source=chatgpt.com \"Content-Security-Policy: require-trusted-types-for directive\"\n[12]: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html?utm_source=chatgpt.com \"HTTP Security Response Headers Cheat Sheet\"\n[13]: https://nvd.nist.gov/vuln/detail/cve-2019-11358?utm_source=chatgpt.com \"CVE-2019-11358 Detail - NVD\"\n[14]: https://api.jquery.com/text/?utm_source=chatgpt.com \".text() | jQuery API Documentation\"\n[15]: https://api.jquery.com/val/?utm_source=chatgpt.com \".val() | jQuery API Documentation\"\n[16]: https://github.com/jquery/jquery/security/advisories/GHSA-gxr4-xjj5-5px2 \"Potential XSS vulnerability in jQuery.htmlPrefilter and related methods · Advisory · jquery/jquery · GitHub\"\n[17]: https://github.com/cure53/DOMPurify?utm_source=chatgpt.com \"DOMPurify - a DOM-only, super-fast, uber-tolerant XSS ...\"\n[18]: https://developer.mozilla.org/en-US/docs/Web/API/HTML_Sanitizer_API?utm_source=chatgpt.com \"HTML Sanitizer API - MDN Web Docs\"\n[19]: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html?utm_source=chatgpt.com \"Cross-Site Request Forgery Prevention Cheat Sheet\"\n[20]: https://api.jquery.com/jQuery.escapeSelector/?utm_source=chatgpt.com \"jQuery.escapeSelector()\"\n[21]: https://api.jquery.com/html/?utm_source=chatgpt.com \".html() | jQuery API Documentation\"\n[22]: https://api.jquery.com/append/?utm_source=chatgpt.com \".append() | jQuery API Documentation\"\n[23]: https://nvd.nist.gov/vuln/detail/cve-2020-11023?utm_source=chatgpt.com \"CVE-2020-11023 Detail - NVD\"\n[24]: https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html?utm_source=chatgpt.com \"Cross Site Scripting Prevention - OWASP Cheat Sheet Series\"\n[25]: https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html?utm_source=chatgpt.com \"DOM based XSS Prevention Cheat Sheet\"\n[26]: https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity?utm_source=chatgpt.com \"Subresource Integrity - Security - MDN Web Docs\"\n[27]: https://www.w3.org/TR/sri-2/?utm_source=chatgpt.com \"Subresource Integrity\"\n[28]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP?utm_source=chatgpt.com \"Content Security Policy (CSP) - HTTP - MDN Web Docs\"\n[29]: https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API?utm_source=chatgpt.com \"Trusted Types API - MDN Web Docs\"\n","core/skills/builtin/security-best-practices/references/javascript-typescript-nextjs-web-server-security.md":"# Next.js (TypeScript/JavaScript) Web Security Spec (Next.js 16.1.x, Node.js 20.9+)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new Next.js backend code (Route Handlers, API Routes, Server Actions, Proxy/Middleware).\n2. **Security review / vulnerability hunting** in existing Next.js repos (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\nTarget scope: Next.js **16.1.x** (latest line shown in the App Router docs) ([Next.js][1]), running on Node.js **20.9+** (per Next.js system requirements). ([Next.js][2])\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session cookies, OAuth tokens, `process.env` dumps, database URLs with credentials).\n* MUST NOT “fix” security by disabling protections (e.g., disabling origin checks, relaxing CORS to `*`, skipping authz checks, turning off cookie security flags, turning off CSP because it’s “hard”).\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and configuration values that justify each claim.\n* MUST treat uncertainty honestly: if a protection might exist in infrastructure (reverse proxy, CDN, WAF, platform headers), report it as “not visible in app code; verify at runtime/config”.\n* MUST assume all request-facing server code is reachable by attackers unless there is a clearly enforced auth boundary (not just “the UI doesn’t link to it”).\n* MUST treat TypeScript types as **non-security boundaries**: types do not validate runtime input; runtime checks are required. ([Next.js][3])\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new Next.js code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default APIs and proven libraries over custom security code.\n* MUST avoid introducing new risky sinks (dynamic code execution, unsafe redirects, serving user files as HTML, SSRF URL fetchers, building SQL strings, etc.).\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a Next.js repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. Deployment entrypoints and environment (Dockerfiles, `package.json` scripts, hosting config).\n2. Next.js config (`next.config.*`), Proxy/Middleware, routing patterns.\n3. Authentication, sessions, cookies.\n4. CSRF protections and state-changing endpoints (Server Actions, Route Handlers, API Routes).\n5. XSS (React + CSP) and unsafe HTML rendering.\n6. Cache/data-leak hazards (static rendering + caching + “use cache”).\n7. File handling (uploads/downloads) and path traversal.\n8. Injection classes (SQL/ORM misuse, command execution, unsafe deserialization).\n9. Outbound requests (SSRF).\n10. Redirect handling (open redirects).\n11. CORS and security headers.\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nIn Next.js backends, untrusted input includes:\n\nApp Router:\n\n* Route Handler params and request data:\n\n  * `context.params` (dynamic segments), search params (`request.url`, `new URL(request.url).searchParams`)\n  * `request.headers`, `request.cookies`\n  * `await request.json()`, `await request.formData()`, `await request.text()`\n* Dynamic APIs used in Server Components/Server Functions:\n\n  * `headers()` and `cookies()` values ([Next.js][4])\n\nPages Router:\n\n* `req.query`, `req.cookies`, `req.body` in `pages/api/*` handlers ([Next.js][3])\n\nPlus:\n\n* Anything from external systems (webhooks, third-party APIs, message queues)\n* Any persisted user content (DB rows) that originated from users\n\n### 2.2 State-changing request\n\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook send), or initiate privileged actions.\n\nSpecial note for Next.js:\n\n* **Server Actions** are invoked via network requests and can mutate state; treat them as state-changing endpoints. ([Next.js][5])\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + function/route name + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common Next.js backend misconfigurations.\n\n### 3.1 Run Next.js in production mode (MUST)\n\n* MUST run `next build` + `next start` (or the managed platform equivalent), not `next dev`. Dev mode has different error/reporting behavior and is not designed for production exposure. ([Next.js][6])\n* MUST ensure `NODE_ENV=production` in production (Next.js defaults `NODE_ENV` based on command; verify the runtime environment). ([Next.js][7])\n\n### 3.2 Put a reverse proxy / edge layer in front when self-hosting (MUST for public internet)\n\n* If self-hosting, MUST place a reverse proxy (e.g., nginx) or equivalent edge layer in front of the Next.js server to handle malformed requests, slow attacks, payload size limits, rate limiting, and similar concerns. ([Next.js][8])\n\n### 3.3 Baseline header/cookie posture (SHOULD)\n\n* SHOULD set a baseline of security headers globally (CSP, `X-Content-Type-Options`, clickjacking defense via CSP `frame-ancestors` and/or `X-Frame-Options`, etc.). Next.js provides guidance for implementing CSP via Proxy/headers. ([Next.js][7])\n* MUST ensure auth/session cookies use secure attributes (`Secure`, `HttpOnly`, `SameSite`) as appropriate. ([Next.js][9])\nIMPORTANT NOTE: Only set `Secure` in production environment. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n\n### 3.4 Clear separation between server-only and client code (MUST)\n\n* MUST prevent secrets and privileged logic from being bundled into client code.\n* MUST treat `NEXT_PUBLIC_*` environment variables as public (browser-exposed and inlined at build time). ([Next.js][7])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### NEXT-DEPLOY-001: Do not run `next dev` in production; ensure production mode behavior\n\nSeverity: High (if production)\n\nNOTE: If they are deploying to a specific Next.js hosting provider, they do not need to worry about this.\n\nRequired:\n\n* MUST NOT deploy `next dev` or any development server mode to production.\n* MUST ensure production builds and production runtime are used for any public deployment. ([Next.js][6])\n\nInsecure patterns:\n\n* `next dev` in Docker `CMD`, Procfile, platform start command.\n* `NODE_ENV=development` in production environment config.\n* Debug/dev-only endpoints or flags exposed publicly.\n\nDetection hints:\n\n* Search `package.json` scripts and deployment manifests for `next dev`.\n* Search infra for `NODE_ENV=development` or missing `NODE_ENV`.\n* Check Kubernetes/PM2/systemd entrypoints for `next dev`.\n\nFix:\n\n* Use `next build` during CI/build and `next start` at runtime (or platform-native build/run).\n* Ensure environment sets `NODE_ENV=production`.\n\nNote:\n\n* Dev mode is fine for local development. Only flag if it is being used as a production entrypoint.\n\n---\n\n### NEXT-SUPPLY-001: Stay on supported Next.js releases; patch quickly for security advisories\n\nSeverity: High (Critical if known-vulnerable version)\n\nRequired:\n\n* MUST run a supported Next.js version line and apply security updates promptly. Next.js documents an LTS/support policy. ([Next.js][10])\n* MUST treat published advisories as urgent upgrade signals (e.g., update to a patched release). ([GitHub][11])\n\nInsecure patterns:\n\n* Running EOL Next.js major/minor without backported security fixes.\n* Ignoring advisories, or pinning `next` to a vulnerable range.\n\nDetection hints:\n\n* Check `package.json` and lockfiles for `next` version.\n* Compare against Next.js support policy and advisories.\n\nIMPORTANT: Any versions older than these minor versions are vulnerable to \"react2shell\" vulnerability (https://nextjs.org/blog/CVE-2025-66478):\n15.0.5\n15.1.9\n15.2.6\n15.3.6\n15.4.8\n15.5.7\n16.0.7\n\nFix:\n\n* Upgrade `next` to a supported and patched version.\n* Add a dependency update process + CI checks.\n\n\n---\n\n### NEXT-SECRETS-001: Secrets MUST NOT be committed or exposed to the browser\n\nSeverity: High (Critical if secret is client-exposed)\n\nRequired:\n\n* MUST store secrets in environment variables or a secret manager; MUST NOT commit `.env*` files.\n* MUST treat `.env*` as sensitive; Next.js warns you “almost never want to commit these files.” ([Next.js][7])\n* MUST treat any `NEXT_PUBLIC_*` environment variable as public and browser-visible (inlined into the client bundle at build time). ([Next.js][7])\n\nInsecure patterns:\n\n* `.env`, `.env.local`, `.env.production` committed to git.\n* `NEXT_PUBLIC_API_KEY`, `NEXT_PUBLIC_SECRET`, `NEXT_PUBLIC_DATABASE_URL`, etc.\n* Rendering `process.env` values into HTML or returning them from API routes.\n\nDetection hints:\n\n* Scan git history and repo files for `.env` content, `DB_PASS=`, `API_KEY=`, `SECRET=`.\n* Grep for `NEXT_PUBLIC_` and review any sensitive-looking names.\n* Search for `process.env` usage in Client Components (`\"use client\"`) and shared modules.\n\nFix:\n\n* Move secrets to server-only env vars (no `NEXT_PUBLIC_` prefix).\n* Ensure `.env*` is ignored and secrets are injected at deploy time.\n* Rotate leaked keys.\n\n---\n\n### NEXT-SECRETS-002: Avoid server-only → client bundling mistakes (server/client boundary is a security boundary)\n\nSeverity: High\n\nRequired:\n\n* MUST ensure server-only modules (DB clients, secret-dependent code) are not imported into Client Components or other client-bundled code paths.\n* SHOULD use server-only patterns/layers (e.g., a dedicated DAL and server-only modules) and treat boundary violations as security bugs. Next.js explicitly discusses the “server-only” concept for sensitive modules. ([Next.js][6])\n\nInsecure patterns:\n\n* Importing DB clients, admin SDKs, or secret-reading modules into `\"use client\"` components.\n* Shared `lib/` modules imported by both server and client code that reference secrets.\n\nDetection hints:\n\n* Search for `\"use client\"` and examine its imports for server-only dependencies.\n* Look for DB client packages (`pg`, `mysql2`, `mongoose`, `prisma`, admin SDKs) imported from `components/` or other client paths.\n* Search for `process.env` access in UI components.\n\nFix:\n\n* Refactor into `lib/server/*` and only import from server contexts (Route Handlers, Server Components, Server Actions).\n* Add an explicit “server-only” guard pattern (and/or tests) to prevent accidental imports.\n\n---\n\n### NEXT-AUTH-001: Authentication/authorization MUST be enforced server-side for every protected action\n\nSeverity: High\n\nRequired:\n\n* MUST enforce authn/authz in server-side code for:\n\n  * Route Handlers (`app/**/route.ts`) ([Next.js][1])\n  * API Routes (`pages/api/**`) ([Next.js][3])\n  * Server Actions (`\"use server\"` functions invoked by clients) ([Next.js][6])\n* MUST NOT rely on client-side checks (hiding UI, route guards on the client) as the only protection.\n\nInsecure patterns:\n\n* Sensitive Route Handlers with no session verification.\n* Server Actions that mutate data but do not validate user identity/permissions.\n* “Authorization” checks in React components only.\n\nDetection hints:\n\n* Enumerate all Route Handlers and API Routes; for each, identify whether it requires auth.\n* Grep for `\"use server\"` and review all exported actions for auth checks.\n* Search for admin actions triggered by query params / form submits.\n\nFix:\n\n* Centralize auth helpers and call them in every protected endpoint/action.\n* Implement least-privilege authorization checks (role/resource ownership) per action.\n\n---\n\n### NEXT-AUTH-002: Proxy/Middleware-based auth MUST NOT create route coverage gaps\n\nSeverity: High\n\nRequired:\n\n* If using **Proxy** or **Middleware** for authentication checks, MUST ensure it covers every route that needs protection.\n* Next.js documentation notes Proxy can use a `matcher`, and for auth it’s recommended Proxy runs on all routes. ([Next.js][12])\n* MUST treat `matcher` mistakes as an auth bypass risk.\n\nInsecure patterns:\n\n* Proxy/Middleware only matches “pages” but not `/api/*`, or only matches some route groups.\n* “Denylist” style matchers that miss alternative request forms (framework-internal variants, RSC navigations, etc.).\n\nDetection hints:\n\n* Inspect `proxy.ts` / `middleware.ts` and its `matcher`.\n* Compare matchers to the full set of routes (including `app/api/**` and `pages/api/**`).\n* Ensure static assets and Next internals are excluded only intentionally, and that sensitive routes are included.\n\nFix:\n\n* Prefer allowlisting protected route prefixes or running Proxy globally and doing internal allow/deny logic.\n* Add integration tests: request protected route without auth and assert denial.\n\nNotes:\n\n* Proxy is commonly used for “optimistic checks”; it is not a complete authorization system by itself. ([Next.js][12])\n\n---\n\n### NEXT-CSRF-001: Cookie-authenticated state-changing endpoints MUST be CSRF-protected\n\nSeverity: High\n\n- IMPORTANT NOTE: If cookies are not being used for auth (ie auth is via Authentication header or other passed token), then there is no CSRF risk.\n\nRequired:\n\n* MUST protect every state-changing endpoint that relies on cookies for auth (POST/PUT/PATCH/DELETE).\n* For **Server Actions**, Next.js performs an Origin/Host comparison to help prevent CSRF; do not disable or weaken it. ([Next.js][5])\n* If Server Actions must be callable from additional trusted origins (e.g., a trusted proxy domain), MUST use `allowedOrigins` with a strict allowlist. ([Next.js][5])\n* For **Route Handlers** and **API Routes**, MUST implement CSRF protections explicitly (tokens and/or strict Origin/Referer + SameSite + custom headers). Route Handlers are an “escape hatch” and require application-level security decisions. ([Next.js][6])\n\nInsecure patterns:\n\n* POST endpoints (including Server Actions) that mutate state and accept cross-site requests with no token/origin checks.\n* `allowedOrigins: ['*']` (or broad wildcards) or “reflect Origin” logic.\n* Using GET requests to change state.\n\nDetection hints:\n\n* Enumerate all state-changing endpoints and determine auth mechanism.\n* Search for `allowedOrigins` and confirm the list is small, specific, and justified. ([Next.js][5])\n* In Route Handlers/API Routes: look for missing CSRF token validation or missing Origin/Referer checks.\n\nFix:\n\n* Implement a CSRF token strategy for cookie-auth endpoints.\n* Keep cookies `SameSite=Lax` or `Strict` when compatible; don’t treat SameSite alone as sufficient.\n* Use strict Origin validation for JSON API endpoints, especially when not using CSRF tokens.\n\nNotes:\n\n* XSS can defeat CSRF protections; CSRF defenses do not replace XSS prevention.\n\n---\n\n### NEXT-SESS-001: Session cookies MUST use secure attributes in production\n\nSeverity: Medium\n\nRequired (production, HTTPS):\n\n* MUST set session/auth cookies with:\n\n  * `Secure: true` (HTTPS-only) IMPORTANT NOTE: Only set `Secure` in production environment. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n  * `HttpOnly: true` (not readable by JS)\n  * `SameSite: 'Lax'` (recommended) or `'Strict'` if compatible\n* Only use `SameSite: 'none'` when you truly need cross-site cookies, and then MUST also set `Secure`. Cookie options are supported in Next.js cookie APIs. ([Next.js][9])\n\nInsecure patterns:\n\n* `secure: false` in production.\n* `httpOnly: false` for auth cookies.\n* `sameSite: 'none'` without a clear need, especially on cookie-authenticated state-changing endpoints.\n\nDetection hints:\n\n* Search for cookie setting sites (`cookies().set(...)`, `Set-Cookie` headers, auth library cookie config).\n* Review cookie options used in Route Handlers and Server Actions. ([Next.js][9])\n\nFix:\n\n* Set secure cookie attributes at the auth/session layer.\n* Reduce cookie scope: avoid wide `domain` unless you explicitly need subdomain-wide cookies.\n\n---\n\n### NEXT-SESS-002: Sessions MUST be bounded and resistant to fixation/replay\n\nSeverity: Low\n\nRequired:\n\n* SHOULD set bounded session lifetimes appropriate to the app.\n* SHOULD rotate session identifiers on login and privilege changes.\n* MUST NOT store sensitive secrets directly in client-readable storage (including cookies that are not encrypted).\n\nInsecure patterns:\n\n* Long-lived admin sessions with no rotation.\n* “Remember me forever” for privileged roles without additional risk controls.\n* Storing access tokens/refresh tokens in non-HttpOnly cookies or localStorage.\n\nDetection hints:\n\n* Review auth library configuration for expiration and rotation.\n* Search for `localStorage.setItem('token'...)` and non-HttpOnly cookie usage.\n\nFix:\n\n* Use short lifetimes for privileged sessions; refresh with rotation.\n* Store only opaque session IDs in cookies; keep sensitive material server-side.\n\n---\n\n### NEXT-INPUT-001: Runtime input validation is mandatory (TypeScript is not validation)\n\nSeverity: High\n\nRequired:\n\n* MUST validate and normalize all attacker-controlled input at runtime (schemas, type checks, bounds).\n* Next.js API Routes explicitly note `req.body` is `any` and must be validated before use. ([Next.js][3])\n* MUST validate Server Action arguments (treat as hostile). ([Next.js][6])\n\nInsecure patterns:\n\n* Trusting `req.body` shape directly.\n* Passing `params.id`/`searchParams` directly into DB queries or file paths.\n* Parsing JSON and then assuming types without validation.\n\nDetection hints:\n\n* Identify endpoints that accept JSON/form input and check for schema validation.\n* Grep for `req.body.` usage and for `await request.json()` usage in Route Handlers; verify validation exists.\n\nFix:\n\n* Add schema validation (e.g., zod/yup/valibot) and reject invalid input with 4xx.\n* Validate IDs as strict types (UUID/int) and enforce length/charset constraints.\n\n---\n\n### NEXT-HEADERS-001: Essential security headers MUST be set (in app or at the edge)\n\nSeverity: Low\n\nRequired (typical web app):\n\n* SHOULD set:\n\n  * CSP (`Content-Security-Policy`) (see NEXT-CSP-001)\n  * `X-Content-Type-Options: nosniff`\n  * Clickjacking defense (`frame-ancestors` in CSP and/or `X-Frame-Options`)\n  * `Referrer-Policy` and `Permissions-Policy` when appropriate\n* MUST ensure cookies are set with secure attributes (see NEXT-SESS-001). ([Next.js][9])\n\nInsecure patterns:\n\n* No security headers anywhere (app or edge).\n* Allowing iframing unintentionally.\n* `Content-Type` sniffing possible due to missing `nosniff`.\n\nDetection hints:\n\n* Check `proxy.ts` / middleware for `response.headers.set(...)`. ([Next.js][7])\n* If not visible in app code, flag as “verify at edge/CDN”.\n\nFix:\n\n* Set headers centrally (Proxy/Middleware or other centralized mechanism).\n* Ensure consistent headers across routes.\n\n---\n\n### NEXT-CSP-001: Use a CSP to reduce XSS impact; prefer nonces for scripts\n\nSeverity: Medium\n\nNOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n\nRequired:\n\n* SHOULD deploy a CSP, ideally with nonces for scripts.\n* SHOULD follow Next.js guidance for CSP implementation (including nonce generation and header application). ([Next.js][7])\n* MUST avoid loosening CSP as a “fix” (e.g., `script-src 'unsafe-inline'`) without explicit risk acceptance.\n\nInsecure patterns:\n\n* CSP missing on apps that display user-generated HTML/markdown.\n* CSP that broadly enables inline scripts or eval without strict justification.\n\nDetection hints:\n\n* Search for `Content-Security-Policy` header setting and examine its directives.\n* Check use of `next/script` and whether a nonce is provided when CSP requires it.\n\nFix:\n\n* Implement CSP per Next.js guidance; use a nonce and apply it consistently.\n* Reduce inline scripts; avoid `eval`.\n\nNotes:\n\n* CSP is defense-in-depth; it does not replace proper output encoding and sanitization.\n\n---\n\n### NEXT-XSS-001: Prevent reflected/stored XSS in React/Next rendering\n\nSeverity: High\n\nRequired:\n\n* MUST rely on React’s default escaping; MUST NOT insert untrusted HTML into the DOM without sanitization.\n* MUST treat these as high-risk sinks:\n\n  * `dangerouslySetInnerHTML`\n  * rendering user-controlled strings into `<script>` tags or event handler attributes\n* MUST avoid serving uploaded HTML as active HTML (serve as attachment or sanitize/transform).\n\nInsecure patterns:\n\n* `<div dangerouslySetInnerHTML={{ __html: userContent }} />` with no sanitizer.\n* Markdown renderers configured to allow raw HTML with no sanitizer.\n* Returning user content with `Content-Type: text/html` from a Route Handler.\n\nDetection hints:\n\n* Search for `dangerouslySetInnerHTML`, `__html:`.\n* Search for template-like string concatenation that builds HTML.\n* Review any “render HTML” or “preview” features.\n\nFix:\n\n* Sanitize untrusted HTML with a well-maintained sanitizer; prefer strict allowlists.\n* Prefer rendering user content as text, not HTML.\n* Add CSP to reduce impact.\n\n---\n\n### NEXT-ACTION-001: Server Actions MUST be treated like public endpoints\n\nSeverity: High (Critical for privileged actions)\n\nRequired:\n\n* MUST apply the same controls as for Route Handlers:\n\n  * authn/authz\n  * input validation\n  * CSRF/origin protections\n  * rate limiting for sensitive actions\n* MUST NOT assume Server Actions are “not reachable” or “internal”.\n* MUST understand Server Action request protections:\n\n  * Next.js compares Origin with host to mitigate CSRF; extra origins must be explicitly allowlisted via `allowedOrigins`. ([Next.js][5])\n\nInsecure patterns:\n\n* `\"use server\"` functions that update DB state with no auth check.\n* Adding overly broad `allowedOrigins` to “make it work”.\n\nDetection hints:\n\n* Grep for `\"use server\"` and inventory all exported actions.\n* Identify any action doing privileged writes; confirm it checks identity and permission.\n\nFix:\n\n* Wrap actions with an authz helper (fail closed).\n* Keep `allowedOrigins` minimal and audited.\n\n---\n\n### NEXT-ACTION-002: Do not accidentally leak secrets through Server Action closure/binding patterns\n\nSeverity: Medium (High if important secrets are exposed)\n\nRequired:\n\n* MUST treat Server Action closed-over values as sensitive and design intentionally.\n* Next.js notes that closed-over values are encrypted/signed, but values passed through `.bind` are not encrypted; do not rely on `.bind` to protect secrets. ([Next.js][6])\n* If using a stable encryption key for Server Actions across deployments, MUST treat it as a secret and store securely (do not commit/log it). ([Next.js][6])\n\nInsecure patterns:\n\n* `myAction.bind(null, process.env.SECRET)` or binding sensitive tokens/IDs that should not be client-influenced.\n* Logging action arguments that include secrets.\n\nDetection hints:\n\n* Search for `.bind(` on Server Action functions.\n* Search for `process.env` usage near Server Actions.\n\nFix:\n\n* Avoid binding secrets into actions; fetch secrets server-side inside the action.\n* Keep action arguments minimal and validated.\n\n---\n\n### NEXT-CACHE-001: Prevent data leaks via static rendering and shared caching\n\nSeverity: High (Critical if cross-user data leak)\n\nRequired:\n\n* MUST ensure pages/endpoints that return user-specific or sensitive data are not statically generated or cached in a shared way.\n* Route Handlers are not cached by default, but GET handlers can opt into caching/static behavior; do not do this for per-user data. ([Next.js][1])\n* MUST treat `use cache` and similar caching mechanisms as potentially cross-user unless explicitly proven private; do not cache per-user DB results in shared caches. ([Next.js][1])\n* SHOULD set explicit `Cache-Control: no-store` / `private` for sensitive responses (auth/session/user data APIs).\n\nInsecure patterns:\n\n* `export const dynamic = 'force-static'` on a route that returns user-specific data. ([Next.js][1])\n* Using `use cache` around a function that queries user-specific data without a per-user cache key. ([Next.js][1])\n* Returning auth/session responses from GET endpoints with caching enabled.\n\nDetection hints:\n\n* Search for `dynamic = 'force-static'`, `revalidate`, `use cache`, `cacheLife`, `unstable_cache`.\n* Inspect all GET Route Handlers that are cached/static and confirm they only return public data.\n* Confirm that use of `cookies()`/`headers()` (dynamic APIs) is not accidentally removed in ways that make a route static. ([Next.js][1])\n\nFix:\n\n* Mark sensitive routes as dynamic and set `Cache-Control: no-store`.\n* Ensure caching keys include user identity if caching is truly needed (and store it in a user-private cache).\n\n---\n\n### NEXT-FILES-001: User uploads MUST be validated, stored safely, and served safely\n\nSeverity: Medium\n\nRequired:\n\n* MUST enforce upload size limits at the edge and in application logic.\n* MUST validate file type using allowlists and content checks (not only extension).\n* MUST store uploads outside the `public/` directory (anything under `public/` is served as static content by default).\n* MUST serve potentially active formats safely (`Content-Disposition: attachment`) unless explicitly intended.\n\nInsecure patterns:\n\n* Accepting arbitrary file types and serving them back inline.\n* Using user-supplied filename as the storage path.\n* Writing uploads into `public/uploads/` and serving them directly.\n\nDetection hints:\n\n* Search for `formData()` / multipart parsing, `fs.writeFile`, storage SDK usage.\n* Look for any write path under `public/`.\n* Look for “download” endpoints that set `Content-Type: text/html` or serve user files inline.\n\nFix:\n\n* Use a dedicated object store (S3/GCS) or a safe server-side directory outside static roots.\n* Generate random server-side filenames; store metadata separately.\n\n---\n\n### NEXT-PATH-001: Prevent path traversal and unsafe file access\n\nSeverity: High\n\nRequired:\n\n* MUST NOT use user-controlled strings as filesystem paths.\n* MUST validate and normalize identifiers; use allowlists and safe base directories.\n* MUST avoid reading arbitrary files based on request parameters.\n\nInsecure patterns:\n\n* `fs.readFile(request.nextUrl.searchParams.get('path'))`\n* `path.join(base, userPath)` without normalization + boundary checks\n\nDetection hints:\n\n* Search for `fs.` usage in Route Handlers/API Routes.\n* Search for `path.join`/`path.resolve` fed by request params.\n\nFix:\n\n* Use opaque IDs that map to server-side stored paths.\n* Enforce that resolved paths remain within an intended base directory.\n* Sanitize and disallow `..` from being used when creating urls\n\n---\n\n### NEXT-SSRF-001: Outbound requests using user-influenced URLs MUST be restricted\n\nSeverity: Medium (High in internal networks)\n\nNOTE: This is mostly only applicable to apps which will be deployed in a cloud/LAN setup or have other http services on the same box. Sometimes the feature requires this functionality unavoidably (webhooks).\n\nRequired:\n\n* MUST treat any server-side `fetch()` to a user-provided URL as high-risk.\n* SHOULD allowlist destinations (hosts/domains) for URL fetch features.\n* SHOULD block:\n\n  * localhost / private IP ranges / link-local\n  * cloud metadata endpoints\n* MUST restrict protocols to `http:` and `https:`.\n* SHOULD set strict timeouts and restrict redirects.\n\nInsecure patterns:\n\n* `await fetch(req.query.url)` or `await fetch((await request.json()).url)`\n* “URL preview” endpoints that fetch arbitrary URLs.\n\nDetection hints:\n\n* Search for `fetch(` in server code and trace where the URL comes from.\n* Look for “webhook tester”, “preview”, “import from URL” features.\n\nFix:\n\n* Parse URL, enforce `http/https`, allowlist hostnames, re-resolve DNS/IP to block private ranges.\n* Set timeouts (AbortSignal) and limit redirects.\n\n---\n\n### NEXT-REDIRECT-001: Prevent open redirects (including auth flows)\n\nSeverity: Low\n\nRequired:\n\n* MUST validate redirect targets derived from untrusted input (e.g., `next`, `redirect`, `returnTo`).\n* SHOULD prefer redirecting only to same-site relative paths.\n* MUST validate any absolute URL against an allowlist.\n* MUST ensure urls are `http` or `https:` schema, disallowing `javascript:` schema\n\nInsecure patterns:\n\n* `redirect(searchParams.get('next')!)`\n* `NextResponse.redirect(new URL(req.nextUrl.searchParams.get('to')!, req.url))` without checks\n\nDetection hints:\n\n* Search for `redirect(` (server components/actions) and `NextResponse.redirect`.\n* Search for `res.redirect(` in API Routes. ([Next.js][3])\n\nFix:\n\n* Only allow relative paths (`/path`) and reject protocol-relative (`//evil.com`) or absolute URLs.\n* If invalid, fall back to a safe default (home/dashboard).\n\n---\n\n### NEXT-CORS-001: CORS must be explicit and least-privilege\n\nSeverity: Medium (High if misconfigured with credentials)\n\nRequired:\n\n* If CORS is not needed, MUST keep it disabled.\n* Next.js API Routes do not set CORS headers by default, meaning they are same-origin by default; only enable CORS when you truly need it. ([Next.js][3])\n* If enabling CORS:\n\n  * MUST allowlist trusted origins (no reflection of arbitrary Origin)\n  * MUST be careful with credentialed requests (cookies); never combine broad origins with credentials.\n  * SHOULD restrict methods and headers.\n\nInsecure patterns:\n\n* `Access-Control-Allow-Origin: *` with `Access-Control-Allow-Credentials: true`\n* Reflecting `Origin` without validation.\n\nDetection hints:\n\n* Search for `Access-Control-Allow-Origin`, `cors`, “CORS” middleware/wrappers.\n* Review preflight `OPTIONS` handlers.\n\nFix:\n\n* Implement strict origin allowlist and minimal methods/headers.\n* Ensure cookies aren’t exposed cross-origin unless necessary and reviewed.\n\n---\n\n### NEXT-WEBHOOK-001: Webhook endpoints MUST verify authenticity using the raw body\n\nSeverity: Medium\n\nRequired:\n\n* MUST verify webhook signatures using the **raw request body** (not a re-serialized parsed object).\n* Next.js notes a use case for disabling body parsing is verifying the raw body of a webhook request. ([Next.js][3])\n\nInsecure patterns:\n\n* Verifying webhook signatures over `JSON.stringify(req.body)` (can change formatting).\n* Accepting webhooks with no signature verification and no allowlist.\n\nDetection hints:\n\n* Find webhook endpoints (`/api/webhook`, `/app/api/**/webhook`).\n* Check whether they use raw body verification.\n\nFix:\n\n* Disable Next.js automatic body parsing only for those webhook routes, read raw bytes safely, verify signature, then parse.\n\n---\n\n### NEXT-INJECT-001: Prevent SQL injection (use parameterized queries / ORM)\n\nSeverity: High\n\nRequired:\n\n* MUST use parameterized queries or an ORM that parameterizes under the hood.\n* MUST NOT build SQL by string concatenation / template strings with untrusted input.\n\nInsecure patterns:\n\n* ``db.query(`SELECT * FROM users WHERE id = ${id}`)``\n* `\"WHERE name = '\" + user + \"'\"`\n\nDetection hints:\n\n* Grep for `SELECT`, `INSERT`, `UPDATE`, `DELETE` strings.\n* Trace untrusted input (`params`, `searchParams`, `req.query`, `req.body`, `request.json()`) into DB calls.\n\nFix:\n\n* Use prepared statements / ORM query APIs.\n* Validate and coerce types before querying.\n\n---\n\n### NEXT-INJECT-002: Prevent OS command injection and unsafe subprocess use\n\nSeverity: Critical to High\n\nRequired:\n\n* MUST avoid executing OS commands with attacker-controlled input.\n* If subprocess is necessary:\n\n  * MUST pass args as an array (not a single shell string)\n  * MUST NOT use `shell: true` with attacker-influenced strings\n  * SHOULD use strict allowlists for any variable component\n\nInsecure patterns:\n\n* `exec(\"convert \" + filename)`\n* `spawn(\"bash\", [\"-c\", userInput])`\n* `spawn(userInput, [\"foo\"])`\n\nDetection hints:\n\n* Search for `child_process`, `exec`, `spawn`, `shell: true`.\n\nFix:\n\n* Use library APIs instead of shell commands.\n* Hard-code commands and allowlist validated parameters (and use `--` to separate flags where supported).\n\n---\n\n### NEXT-INJECT-003: Avoid dynamic code execution and unsafe deserialization\n\nSeverity: High to Critical\n\nRequired:\n\n* MUST NOT use `eval`, `new Function`, `vm.runIn*` on untrusted strings.\n* MUST treat deserializing complex formats (YAML, XML, custom serialization) as risky; use safe parsers and strict schemas.\n\nInsecure patterns:\n\n* `eval(req.body.code)`\n* Parsing YAML from user input with a non-safe schema.\n\nDetection hints:\n\n* Search for `eval(`, `new Function`, `vm.`, `require(` with non-literals.\n* Search for `js-yaml`, XML parsers, custom serializer usage on untrusted input.\n\nFix:\n\n* Remove dynamic execution; use safe interpreters or strict parsers.\n* Validate and constrain input.\n\n---\n\n### NEXT-LOG-001: Logging MUST NOT leak secrets or sensitive headers\n\nSeverity: Medium\n\nRequired:\n\n* MUST NOT log:\n\n  * `Authorization` headers\n  * cookies / session tokens\n  * request bodies containing credentials\n  * environment variables or configuration dumps\n* SHOULD implement structured logging with redaction.\n\nInsecure patterns:\n\n* `console.log(req.headers)` in auth endpoints\n* `console.log(process.env)` in server code\n\nDetection hints:\n\n* Search for `console.log(`, `logger.info(`, `debug(` in server routes/actions.\n* Check for logs of headers/cookies/body.\n\nFix:\n\n* Redact sensitive fields; log only what is needed for debugging.\n* Use safe error messages for clients; keep detail server-side only.\n\n---\n\n### NEXT-ERROR-001: Error handling MUST avoid leaking implementation details in production\n\nSeverity: Low\n\nRequired:\n\n* MUST not expose stack traces or internal error details to end users in production.\n* Ensure production mode behavior (Next.js production error handling differs from dev). ([Next.js][6])\n\nInsecure patterns:\n\n* Returning `err.stack` in JSON responses.\n* Showing detailed exception data to unauthenticated users.\n\nDetection hints:\n\n* Search for `res.status(500).json(err)` or `return Response.json(err)`.\n* Verify error responses are sanitized.\n\nFix:\n\n* Return generic error messages to clients; log details server-side with redaction.\n\n---\n\n### NEXT-PROXY-001: Proxy/Middleware must not introduce header smuggling or unsafe header forwarding\n\nSeverity: Medium\n\nRequired:\n\n* MUST be careful when copying/forwarding request headers upstream:\n\n  * Do not forward attacker-controlled `x-forwarded-*` headers unless you have a trusted proxy chain.\n  * Do not forward `Authorization`/cookies to unrelated outbound services.\n* Next.js Proxy patterns often mutate headers; ensure this doesn’t create security issues.\n\nInsecure patterns:\n\n* Blindly cloning all request headers to an outbound `fetch()` call.\n* Trusting `x-forwarded-host` or `host` to construct sensitive absolute URLs without allowlisting.\n\nDetection hints:\n\n* Search `headers()` and `request.headers` usage (especially for URL building). ([Next.js][4])\n* Search Proxy/Middleware for header rewrites.\n\nFix:\n\n* Allowlist forwarded headers explicitly.\n* Validate hostnames before using them to build callback URLs or redirects.\n\n---\n\n### NEXT-HOST-001: Host/Origin-derived URL construction MUST be allowlisted\n\nSeverity: Medium\n\nRequired:\n\n* MUST NOT generate security-sensitive absolute URLs (password reset links, OAuth callback URLs, email verification links) directly from unvalidated `Host` headers.\n* For Server Actions, Origin/Host matching is part of CSRF mitigation; do not weaken it. ([Next.js][5])\n\nInsecure patterns:\n\n* `const base = \"https://\" + request.headers.get(\"host\")`\n* Using unvalidated `x-forwarded-host` for absolute URL generation.\n\nDetection hints:\n\n* Grep for `.get('host')`, `.get('x-forwarded-host')`, and absolute URL building.\n* Review auth-related email link generation code.\n\nFix:\n\n* Use a configured, allowlisted canonical app origin (e.g., `APP_ORIGIN=https://example.com`).\n* Allowlist hostnames; fail closed.\n\n---\n\n### NEXT-DOS-001: Rate limiting and resource controls MUST exist for abuse-prone endpoints\n\nSeverity: Medium\n\nRequired:\n\n* SHOULD implement rate limiting/throttling for:\n\n  * login, password reset, signup\n  * expensive Server Actions\n  * webhook ingestion\n* MUST implement request size limits (see NEXT-LIMITS-001).\n* If self-hosting, MUST rely on reverse proxy for additional protections. ([Next.js][8])\n\nInsecure patterns:\n\n* No throttling on login/reset endpoints.\n* Expensive actions callable without auth or with unlimited frequency.\n\nDetection hints:\n\n* Identify auth endpoints and check for rate limiting.\n* Search for “send email”, “charge”, “generate report” flows.\n\nFix:\n\n* Add edge rate limiting and app-level user/IP throttles.\n* Add job queues for heavy work; return 202 when appropriate.\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* Production misconfig:\n\n  * `next dev`, `NODE_ENV=development`, dev-only start commands ([Next.js][7])\n* Secrets exposure:\n\n  * `.env` committed, `NEXT_PUBLIC_` on sensitive variables ([Next.js][7])\n  * `process.env` used in `\"use client\"` modules\n* Auth coverage:\n\n  * `app/**/route.ts` or `pages/api/**` with no auth checks ([Next.js][1])\n  * `\"use server\"` actions with DB writes and no authz ([Next.js][6])\n  * `proxy.ts` / `middleware.ts` matchers that exclude sensitive routes ([Next.js][12])\n* CSRF:\n\n  * cookie-auth POST/PUT/PATCH/DELETE with no token/origin checks\n  * `serverActions.allowedOrigins` too broad ([Next.js][5])\n* XSS:\n\n  * `dangerouslySetInnerHTML`, raw HTML markdown rendering\n  * missing CSP / overly permissive CSP ([Next.js][7])\n* Caching/data leak:\n\n  * `dynamic = 'force-static'` on sensitive GET handlers ([Next.js][1])\n  * `use cache`, `cacheLife`, `unstable_cache` around user-specific data ([Next.js][1])\n* Files:\n\n  * writing uploads under `public/`\n  * `fs.readFile` / `path.join` with request input\n* SSRF:\n\n  * `fetch(userProvidedUrl)` from Route Handlers / Server Actions\n* Redirect:\n\n  * `redirect(searchParams.get('next'))`, `NextResponse.redirect(...)`, `res.redirect(req.query.next)` ([Next.js][3])\n* CORS:\n\n  * wildcard origins, origin reflection, credentials + broad origins ([Next.js][3])\n* Limits:\n\n  * API routes with `bodyParser: false` and no raw-body verification for webhooks ([Next.js][3])\n  * `serverActions.bodySizeLimit` raised without justification ([Next.js][5])\n* Dependency hygiene:\n\n  * old `next` versions that conflict with support policy/advisories ([Next.js][10])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (HTML/DOM, SQL, subprocess, files, redirect, outbound HTTP)\n* protective controls present (schema validation, allowlists, middleware/proxy checks, authz helpers, edge protections)\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary framework documentation (Next.js):\n\n* Next.js Docs: Installation (system requirements / Node version) — `https://nextjs.org/docs/app/getting-started/installation`\n* Next.js Docs: Route Handlers — `https://nextjs.org/docs/app/getting-started/route-handlers`\n* Next.js Docs: API Routes (Pages Router) — `https://nextjs.org/docs/pages/building-your-application/routing/api-routes`\n* Next.js Docs: Environment Variables — `https://nextjs.org/docs/pages/guides/environment-variables`\n* Next.js Docs: Data Security — `https://nextjs.org/docs/app/guides/data-security`\n* Next.js Docs: Content Security Policy — `https://nextjs.org/docs/app/guides/content-security-policy`\n* Next.js Docs: Proxy — `https://nextjs.org/docs/app/getting-started/proxy`\n* Next.js Docs: `serverActions.allowedOrigins` and `serverActions.bodySizeLimit` — `https://nextjs.org/docs/app/api-reference/config/next-config-js/serverActions`\n* Next.js Docs: `cookies()` — `https://nextjs.org/docs/app/api-reference/functions/cookies`\n* Next.js Docs: `headers()` — `https://nextjs.org/docs/app/api-reference/functions/headers`\n* Next.js Docs: Self-hosting (reverse proxy guidance) — `https://nextjs.org/docs/pages/guides/self-hosting`\n* Next.js Docs: Support policy (supported versions/LTS) — `https://nextjs.org/docs/support-policy`\n\nNext.js security guidance & advisories:\n\n* Next.js Blog: How to think about security in Next.js — `https://nextjs.org/blog/security-nextjs-server-components-actions`\n* GitHub Security Advisory: Next.js DoS via Server Components / Server Actions (CVE-2026-23864) — `https://github.com/advisories/GHSA-fq29-rrrv-cq2m`\n* Next.js Blog: Security update (example security advisory context) — `https://nextjs.org/blog/security-update`\n\nGeneral web security references (recommended baseline):\n\n* OWASP Cheat Sheet Series (CSRF, Session Management, XSS Prevention, SSRF Prevention, File Upload, HTTP Headers) — `https://cheatsheetseries.owasp.org/`\n\n[1]: https://nextjs.org/docs/app/getting-started/route-handlers \"Getting Started: Route Handlers | Next.js\"\n[2]: https://nextjs.org/docs/app/getting-started/deploying?utm_source=chatgpt.com \"Getting Started: Deploying\"\n[3]: https://nextjs.org/docs/pages/building-your-application/routing/api-routes \"Routing: API Routes | Next.js\"\n[4]: https://nextjs.org/docs/app/api-reference/functions/headers \"Functions: headers | Next.js\"\n[5]: https://nextjs.org/docs/app/api-reference/config/next-config-js/serverActions \"next.config.js: serverActions | Next.js\"\n[6]: https://nextjs.org/blog/security-nextjs-server-components-actions \"How to Think About Security in Next.js | Next.js\"\n[7]: https://nextjs.org/docs/pages/guides/environment-variables \"Guides: Environment Variables | Next.js\"\n[8]: https://nextjs.org/docs/pages/guides/self-hosting?utm_source=chatgpt.com \"Guides: Self-Hosting\"\n[9]: https://nextjs.org/docs/app/api-reference/functions/cookies \"Functions: cookies | Next.js\"\n[10]: https://nextjs.org/blog/next-16?utm_source=chatgpt.com \"Next.js 16\"\n[11]: https://github.com/vercel/next.js/security/advisories/GHSA-9g9p-9gw9-jx7f?utm_source=chatgpt.com \"Denial of Service in Image Optimizer · Advisory\"\n[12]: https://nextjs.org/docs/pages/guides/authentication \"Guides: Authentication | Next.js\"\n","core/skills/builtin/security-best-practices/references/javascript-typescript-react-web-frontend-security.md":"# React (JavaScript/TypeScript) Web Security Spec (React 19.x, TypeScript 5.x)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new React code.\n2. **Security review / vulnerability hunting** in existing React code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, OAuth client secrets, private keys, session cookies, JWTs, signing keys).\n\n  * Frontend note: anything shipped to the browser is observable by end users and attackers (view-source, devtools, proxies); never treat client code or “env vars in the bundle” as secret. ([create-react-app.dev][1])\n* MUST NOT “fix” security by disabling protections (e.g., turning off CSP to “make it work”, adding `unsafe-inline`/`unsafe-eval` without a documented, constrained plan, disabling CSRF protections when using cookies, widening CORS, skipping sanitization, or “temporary” bypasses that ship). ([OWASP Cheat Sheet Series][2])\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and configuration values that justify the claim.\n* MUST treat uncertainty honestly: if a protection might exist in infra (CDN/WAF/reverse proxy), report it as “not visible in app code; verify via runtime headers / edge config”.\n* MUST assume any data that crosses a trust boundary (URL, storage, network, postMessage, third-party scripts) can be attacker-influenced unless proven otherwise (see §2.1).\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new React code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default APIs and proven libraries over custom security code.\n* MUST avoid introducing new risky sinks (raw HTML insertion, direct DOM sinks like `innerHTML`, dynamic code execution, untrusted redirects/navigation, third‑party script injection, unsafe token storage, etc.). ([MDN Web Docs][3])\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a React repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. App entrypoints, build tooling (Vite/Webpack/CRA/Next), deployment configs, CDN/static hosting config.\n2. Secrets & configuration exposure (env vars, runtime config injection, source maps).\n3. Rendering of untrusted data (XSS/DOM XSS), especially `dangerouslySetInnerHTML`, markdown/HTML renderers, URL attributes.\n4. Direct DOM usage and dangerous JS execution (`innerHTML`, `eval`, `new Function`, `document.write`, etc.).\n5. Auth & session patterns (token storage, cookies, CSRF interactions, OAuth flows).\n6. Network layer (axios/fetch wrappers, dynamic base URLs, credentialed requests, data exfil risks).\n7. Navigation & redirect handling (open redirects, `window.location`, `target=_blank`, `window.open`).\n8. Third-party scripts/tags/analytics and integrity controls (CSP, SRI).\n9. Service worker/PWA behavior (HTTPS, caching rules, update strategy).\n10. Security headers posture (CSP, clickjacking, nosniff, referrer policy) in app or at the edge. ([OWASP Cheat Sheet Series][2])\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nExamples include:\n\n* URL-derived data: `window.location`, query params, hash fragments, route params.\n* Any data from browser storage: `localStorage`, `sessionStorage`, `IndexedDB` (including data previously written by the app—because XSS or extensions can tamper with it). ([OWASP Cheat Sheet Series][4])\n* Any data from cross-window messaging: `window.postMessage` payloads. ([OWASP Cheat Sheet Series][4])\n* Any data from remote APIs, webhooks proxied to the client, GraphQL responses, CMS content, feature flag services.\n* Any persisted user content (profiles, comments, rich text, markdown) rendered in the UI.\n* Any data produced by third-party scripts or tag managers (treat as untrusted unless strongly controlled). ([OWASP Cheat Sheet Series][5])\n\n### 2.2 State-changing request (frontend perspective)\n\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook), or initiate privileged actions.\n\nFrontend-specific note:\n\n* State changes are often triggered by `fetch/axios` calls or form submissions. If authentication is cookie-based, these calls can be CSRF-relevant (§4 REACT-CSRF-001). ([OWASP Cheat Sheet Series][6])\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + component/function + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common React frontend misconfigurations.\n\n### 3.1 Production build and configuration hygiene (MUST)\n\n* MUST ship a production build (minified, no dev-only overlays/tools, correct mode flags).\n* MUST ensure build-time configuration does not embed secrets into the shipped JS/HTML/CSS. Build-time “environment variables” are not secret; treat them as public. ([create-react-app.dev][1])\n* SHOULD treat source maps as sensitive operational artifacts:\n\n  * Either don’t publish them publicly, or publish them only where intended (e.g., behind auth or to an error-reporting provider), because they can reveal code structure and internal URLs.\n\n### 3.2 Browser-enforced protections (SHOULD, but baseline expectation for modern apps)\n\n* SHOULD deploy a CSP as defense-in-depth against XSS, and keep it compatible with your React build (avoid `unsafe-inline` and `unsafe-eval` unless strictly necessary and documented). ([OWASP Cheat Sheet Series][2])\n* SHOULD use Subresource Integrity (SRI) for any third-party script/style loaded from a CDN (or self-host instead). ([MDN Web Docs][7])\n* SHOULD enable clickjacking defenses via `frame-ancestors` (CSP) and/or `X-Frame-Options`, unless embedding is an explicit product requirement. ([MDN Web Docs][8])\n\n### 3.3 High-risk features baseline (MUST if used)\n\n* If rendering any user-provided HTML/markdown/rich text:\n\n  * MUST sanitize before insertion and avoid raw DOM sinks. ([OWASP Cheat Sheet Series][9])\n* If using service workers / PWA:\n\n  * MUST serve over HTTPS and implement a safe caching/update strategy (service workers are powerful request/response proxies). ([MDN Web Docs][10])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### REACT-CONFIG-001: Never embed secrets in the client bundle (env vars are public)\n\nSeverity: Critical (if secrets exposed)\n\nRequired:\n\n* MUST NOT place secrets in React code, in `public/` assets, or in build-time environment variables intended for client consumption.\n* MUST assume any value available to the React app at runtime can be extracted by an attacker.\n\nInsecure patterns:\n\n* Using build-time env vars for secrets:\n\n  * `process.env.REACT_APP_*` containing private keys or credentials.\n  * `import.meta.env.VITE_*` containing secrets.\n* Hard-coded secrets in JS/TS, `.env` committed, or secrets in `public/config.json` served to all users.\n\nDetection hints:\n\n* Search for:\n\n  * `REACT_APP_`, `VITE_`, `NEXT_PUBLIC_`, `process.env.`, `import.meta.env.`\n  * `apiKey`, `secret`, `token`, `private`, `password`, `client_secret`\n* Inspect `public/` for runtime config JSON.\n\nFix:\n\n* Move secrets server-side (API, BFF, serverless function).\n* Use a backend to mint short-lived, scoped tokens if the browser needs to call third-party APIs.\n\nNotes:\n\n* CRA explicitly warns not to store secrets and notes env vars are embedded into the build and visible to anyone inspecting files. ([create-react-app.dev][1])\n* Vite explicitly notes that variables exposed to client code end up in the client bundle and should not contain sensitive info. ([vitejs][11])\n\n---\n\n### REACT-XSS-001: Do not use `dangerouslySetInnerHTML` with untrusted content (sanitize or avoid)\n\nSeverity: High (Only if you can prove attacker-controlled HTML reaches it)\n\nRequired:\n\n* MUST avoid `dangerouslySetInnerHTML` unless absolutely necessary.\n* If it must be used:\n\n  * MUST sanitize untrusted HTML with a proven sanitizer (e.g., DOMPurify) and an allowlist-oriented configuration.\n  * MUST keep the sanitization logic centralized and heavily reviewed.\n  * SHOULD add a CSP and consider Trusted Types (see REACT-TT-001).\n\nInsecure patterns:\n\n* `<div dangerouslySetInnerHTML={{ __html: userHtml }} />` where `userHtml` is from API/URL/storage.\n* “Sanitization” done with regexes, ad-hoc stripping, or incomplete allowlists.\n\nDetection hints:\n\n* Grep: `dangerouslySetInnerHTML`, `__html:`\n* Trace the origin of the HTML string (API/CMS/URL/localStorage).\n\nFix:\n\n* Replace with safe rendering:\n\n  * Render structured data as React elements/components instead of HTML strings.\n  * If rich text is required, sanitize with DOMPurify (or equivalent) and render the sanitized output.\n* Add CSP; remove dangerous sinks where possible.\n\nNotes:\n\n* React explicitly warns that `dangerouslySetInnerHTML` is dangerous and can introduce XSS if misused. ([React][12])\n* OWASP explicitly calls out React’s `dangerouslySetInnerHTML` without sanitization as a common framework “escape hatch” pitfall. ([OWASP Cheat Sheet Series][9])\n* DOMPurify describes itself as an XSS sanitizer for HTML/SVG/MathML. ([GitHub][13])\n\n---\n\n### REACT-XSS-002: Rely on React’s escaping-by-default behavior; do not bypass it\n\nSeverity: High (when bypassed)\n\nRequired:\n\n* MUST render untrusted strings via normal JSX interpolation (`{value}`) and React props, which are escaped by default.\n* MUST NOT build HTML strings from untrusted data and then inject them into the DOM via any means.\n* SHOULD treat any “escape hatch” as high risk and require review.\n\nInsecure patterns:\n\n* Converting untrusted text into HTML and injecting it:\n\n  * `element.innerHTML = userValue`\n  * `document.write(userValue)`\n  * `insertAdjacentHTML(..., userValue)`\n\nDetection hints:\n\n* Grep for DOM sinks: `innerHTML`, `outerHTML`, `insertAdjacentHTML`, `document.write`, `DOMParser`, `createContextualFragment`.\n\nFix:\n\n* Render text content through React (JSX) so it is escaped.\n* If you truly need HTML, sanitize and apply REACT-XSS-001 + REACT-TT-001.\n\nNotes:\n\n* React documentation (JSX) states that React DOM escapes values embedded in JSX before rendering to help prevent injection attacks. ([React][14])\n\n---\n\n### REACT-DOM-001: Avoid DOM XSS injection sinks in React code (use safe alternatives)\n\nSeverity: High\n\nRequired:\n\n* MUST avoid direct DOM injection sinks, even outside React rendering, unless strongly controlled.\n* If a DOM sink is required:\n\n  * MUST ensure inputs are trusted/validated/sanitized.\n  * SHOULD enforce Trusted Types (REACT-TT-001).\n\nInsecure patterns:\n\n* `someEl.innerHTML = untrusted`\n* `document.write(untrusted)`\n* `new DOMParser().parseFromString(untrusted, 'text/html')` followed by insertion\n\nDetection hints:\n\n* Grep for: `innerHTML`, `outerHTML`, `document.write`, `DOMParser`, `Range().createContextualFragment`, `insertAdjacentHTML`\n\nFix:\n\n* Prefer:\n\n  * `textContent` for text insertion.\n  * React rendering rather than manual DOM manipulation.\n  * A vetted sanitizer for any required HTML parsing.\n\nNotes:\n\n* Trusted Types documentation defines HTML sinks like `Element.innerHTML` and `document.write()` as injection sinks that can execute script when given attacker-controlled input. ([MDN Web Docs][3])\n* OWASP HTML5 guidance recommends using `textContent` instead of `innerHTML` for assigning untrusted data. ([OWASP Cheat Sheet Series][4])\n\n---\n\n### REACT-URL-001: Validate and constrain untrusted URLs used in `href`, `src`, navigation, and redirects\n\nSeverity: High Only when you can prove they are attacker controlled\n\nRequired:\n\n* MUST treat any URL derived from untrusted input as dangerous.\n* MUST allowlist schemes and (when applicable) hosts:\n\n  * Typically allow only `https:` (and maybe `http:` for localhost/dev) and relative URLs for in-app navigation.\n  * MUST explicitly block `javascript:` and dangerous `data:` uses unless you have specialized validation and a clear use case.\n* SHOULD prefer same-site relative paths (e.g., `/settings`) over absolute URLs.\n* MUST validate “returnTo/next/redirect” parameters (see REACT-REDIRECT-001).\n\nInsecure patterns:\n\n* `<img src={userProvidedUrl}>...` (can be used for tracking / data exfil; also risky if used for scripts/iframes)\n* `window.location = next`\n* `navigate(next)` where `next` comes from query params without validation\n\nDetection hints:\n\n* Search for:\n\n  * `href={`, `src={`, `window.location`, `location.href`, `window.open`, `navigate(`, `redirectTo`, `returnTo`, `next=`\n* Track whether the value is derived from URL/query/storage/API.\n\nFix:\n\n* Implement a shared `safeUrl()` utility:\n\n  * Parse with `new URL(value, base)`\n  * Enforce scheme allowlist and host allowlist (or enforce same-origin)\n  * For redirects: allow only relative paths (starting with `/`) or a strict allowlist of absolute origins.\n* Fall back to a safe default when validation fails.\n\nNotes:\n\n* OWASP explicitly notes React’s `dangerouslySetInnerHTML` risk and also states React cannot safely handle `javascript:` or `data:` URLs without specialized validation. ([OWASP Cheat Sheet Series][9])\n\n---\n\n### REACT-MARKUP-001: Markdown / rich text rendering must be configured safely\n\nSeverity: Medium\n\nRequired:\n\n* MUST assume markdown/rich text can be attacker-controlled if it comes from users or CMS.\n* MUST ensure raw HTML is not rendered unless sanitized.\n* SHOULD prefer markdown renderers that:\n\n  * Do not allow raw HTML by default, or\n  * Can be configured to disallow raw HTML, or\n  * Sanitize HTML output before rendering.\n\nInsecure patterns:\n\n* Markdown rendering with “raw HTML passthrough” enabled (e.g., options/plugins that allow HTML).\n* Rendering user-provided SVG/MathML/HTML inline without sanitization.\n\nDetection hints:\n\n* Search for common libraries and risky options:\n\n  * `marked`, `markdown-it`, `react-markdown`, `rehype-raw`, `sanitize: false`, `allowDangerousHtml`, etc.\n* Look for `dangerouslySetInnerHTML` used with “markdown output”.\n\nFix:\n\n* Disable raw HTML passthrough.\n* Sanitize output with a proven sanitizer (e.g., DOMPurify) before rendering.\n\nNotes:\n\n* OWASP XSS guidance emphasizes that framework escape hatches require output encoding and/or HTML sanitization. ([OWASP Cheat Sheet Series][9])\n\n---\n\n### REACT-TT-001: Use Trusted Types (with CSP) to harden DOM XSS sinks where feasible\n\nSeverity: Low\n\nRequired:\n\n* SHOULD consider enabling Trusted Types in report-only mode first, then enforce once violations are addressed.\n* SHOULD centralize Trusted Types policies and treat them as high-risk code requiring review.\n* MUST NOT create permissive policies that simply “pass through” untrusted strings.\n\nInsecure patterns:\n\n* A Trusted Types policy that returns the raw string without sanitization for HTML sinks.\n* Many scattered policies across the codebase (hard to audit).\n\nDetection hints:\n\n* Search for:\n\n  * `trustedTypes.createPolicy`\n  * CSP directives: `require-trusted-types-for`, `trusted-types`\n* Search for remaining DOM sinks (REACT-DOM-001).\n\nFix:\n\n* Implement a small number of tightly scoped policies:\n\n  * HTML policy uses sanitizer (DOMPurify or equivalent).\n  * Script URL policy uses strict allowlists.\n* Run in report-only mode, fix violations, then enforce.\n\nNotes:\n\n* MDN describes Trusted Types as a way to ensure input is transformed (commonly sanitized) before being passed to injection sinks, and highlights HTML sinks (`innerHTML`, `document.write`) and JS URL sinks (`script.src`). ([MDN Web Docs][3])\n* The W3C Trusted Types spec frames this as reducing DOM XSS risk by locking down sinks to typed values created by reviewed policies. ([W3C][15])\n\n---\n\n### REACT-CSP-001: Deploy and maintain a CSP as defense-in-depth (especially when rendering untrusted content)\n\nSeverity: Medium to High\n\nRequired:\n\n* SHOULD deploy CSP in production; MUST do so for apps that render untrusted content or integrate third-party scripts.\n* SHOULD avoid `unsafe-inline` and `unsafe-eval` when possible.\n* SHOULD use CSP nonces/hashes for inline scripts if needed, and keep policy realistic.\n* SHOULD use CSP to require/encourage SRI where appropriate.\n\nInsecure patterns:\n\n* No CSP at all on the app shell (SPA entry HTML).\n* CSP that relies on `unsafe-inline`/`unsafe-eval` broadly without justification.\n* `script-src *` or overly broad sources.\n\nDetection hints:\n\n* Look for CSP configuration:\n\n  * Server/CDN config, headers in `index.html` responses, or framework config.\n* If absent in repo, mark as “verify at edge”.\n\nFix:\n\n* Add CSP via HTTP response headers (preferred).\n* Start with report-only to reduce breakage, then enforce.\n\nNotes:\n\n* OWASP describes CSP as “defense in depth” against XSS and notes it can help enforce SRI even on static sites, but should not be the only defense. ([OWASP Cheat Sheet Series][2])\n\n---\n\n### REACT-SRI-001: Use Subresource Integrity (SRI) for third-party scripts and styles (or self-host)\n\nSeverity: Low\n\nRequired:\n\n* MUST treat third-party JS as equivalent to running arbitrary code in your origin.\n* If loading from a CDN or third party:\n\n  * SHOULD use SRI (`integrity=...`) and `crossorigin` where applicable.\n  * SHOULD pin exact versions (avoid “latest” URLs).\n  * SHOULD prefer self-hosting for critical code.\n\nInsecure patterns:\n\n* `<script src=\"https://cdn.example.com/lib/latest.js\"></script>` with no integrity.\n* Tag managers that dynamically load arbitrary scripts without governance.\n\nDetection hints:\n\n* Search in `public/index.html`, templates, or SSR wrappers for:\n\n  * `<script src=`, `<link rel=\"stylesheet\" href=`\n  * Tag manager snippets (GTM, Segment, etc.)\n* Identify scripts loaded dynamically in runtime JS.\n\nFix:\n\n* Add SRI hashes for stable third-party assets or self-host.\n* Apply governance controls for tag managers (see REACT-3P-001).\n\nNotes:\n\n* MDN describes SRI as a security feature enabling browsers to verify fetched resources (e.g., from a CDN) haven’t been manipulated by checking a cryptographic hash. ([MDN Web Docs][7])\n* OWASP CSP guidance notes CSP can enforce SRI and is useful even on static sites. ([OWASP Cheat Sheet Series][2])\n\n---\n\n### REACT-3P-001: Third-party JavaScript and tag managers must be minimized and governed\n\nSeverity: High\n\nRequired:\n\n* MUST minimize third-party scripts and treat each as a supply-chain risk.\n* MUST know exactly what third-party JS executes in your origin and why.\n* SHOULD implement governance:\n\n  * Review and pin versions (or mirror in-house).\n  * Restrict data access (data-layer approach).\n  * Use SRI and CSP; consider sandboxing untrusted UI in iframes where possible.\n\nInsecure patterns:\n\n* Unreviewed analytics/ads scripts running with full access to DOM, cookies, storage, and user data.\n* Tag managers that can be changed by non-engineering roles with no change control.\n\nDetection hints:\n\n* Search for common vendor snippets in HTML/JS:\n\n  * GTM, Segment, Hotjar, FullStory, etc.\n* Look for dynamic script insertion:\n\n  * `document.createElement('script')`, `.src = ...`, `.appendChild(script)`\n\nFix:\n\n* Reduce to only necessary vendors.\n* Where feasible:\n\n  * Self-host or mirror scripts.\n  * Use SRI.\n  * Limit data exposure via a controlled data layer.\n\nNotes:\n\n* OWASP notes third-party JS server compromise can inject malicious JS, and highlights risks like arbitrary code execution and disclosure of sensitive info to third parties. ([OWASP Cheat Sheet Series][5])\n\n---\n\n### REACT-AUTH-001: Token and session handling must be resilient to XSS (avoid sensitive storage in Web Storage)\n\nSeverity: Medium\n\nRequired:\n\n* SHOULD avoid storing session identifiers or long-lived tokens in `localStorage` (and generally in Web Storage) because XSS can exfiltrate them.\n* If tokens must exist client-side:\n\n  * SHOULD prefer in-memory storage with short lifetimes and refresh mechanisms.\n  * MUST scope and rotate tokens; avoid long-lived bearer tokens in persistent storage.\n* SHOULD prefer HTTPOnly cookies for session tokens when possible (requires CSRF strategy: see REACT-CSRF-001).\n\nInsecure patterns:\n\n* `localStorage.setItem('token', ...)` / `sessionStorage.setItem('token', ...)` for auth tokens.\n* Persisting refresh tokens in `localStorage`.\n* Treating data from Web Storage as trusted.\n\nDetection hints:\n\n* Grep for: `localStorage.`, `sessionStorage.`, `setItem(`, `getItem(`, `token`, `jwt`, `refresh`\n* Search auth code for “remember me” storing tokens persistently.\n\nFix:\n\n* Move to HTTPOnly cookies (server change) + CSRF protections, or use short-lived in-memory tokens.\n* Reduce token scope and lifetime.\n\nNotes:\n\n* OWASP HTML5 guidance recommends avoiding sensitive info and session identifiers in local storage and warns that a single XSS can steal all data in Web Storage. ([OWASP Cheat Sheet Series][4])\n* OAuth browser-based apps guidance discusses that tokens stored in persistent browser storage like localStorage can be accessible to malicious JS (e.g., via XSS). ([IETF Datatracker][16])\n\n---\n\n### REACT-CSRF-001: Cookie-authenticated, state-changing requests MUST be CSRF-protected\n\nSeverity: High\n\nNOTE: If the application does not use cookie based auth (using Authentication header for example), then CSRF is not a concern.\n\nRequired:\n\n* If the app relies on cookies for authentication:\n\n  * MUST protect state-changing requests (POST/PUT/PATCH/DELETE) against CSRF.\n  * SHOULD include a CSRF token mechanism (synchronizer token or double-submit cookie) or other robust pattern appropriate to the backend.\n  * SHOULD use SameSite cookies as defense-in-depth, not as the sole defense.\n\nInsecure patterns:\n\n* `fetch('/api/transfer', { method: 'POST', credentials: 'include' })` with no CSRF token/header, relying only on cookies.\n* Using GET for state-changing operations.\n\nDetection hints:\n\n* Enumerate state-changing network calls and check:\n\n  * Is `credentials: 'include'` or `withCredentials: true` used?\n  * Is a CSRF token header included (e.g., `X-CSRF-Token`)?\n* Search for “csrf” utilities; if absent, treat as suspicious.\n\nFix:\n\n* Add CSRF token flow:\n\n  * Fetch token from a safe endpoint and attach to state-changing requests.\n  * Validate server-side.\n* Keep SameSite cookies and Origin/Referer validation as defense-in-depth.\n\nNotes:\n\n* OWASP CSRF guidance explains SameSite behavior (Lax/Strict/None) as a defense-in-depth technique and why Lax is often the usability/security balance, but it is not a complete substitute for CSRF protections. ([OWASP Cheat Sheet Series][6])\n\n---\n\n### REACT-AUTHZ-001: Do not rely on frontend-only authorization\n\nSeverity: High (only if used as primary protection)\n\nRequired:\n\n* MUST treat all frontend authorization checks as UX only.\n* MUST enforce authorization on the server for any protected resource or action.\n\nInsecure patterns:\n\n* “Protected” actions hidden in UI but callable by API without server checks.\n* Client checks like `if (user.isAdmin) { showAdminPanel(); }` with no server-side enforcement.\n\nDetection hints:\n\n* Look for UI gating around sensitive actions and verify server endpoints enforce authorization.\n* In a frontend-only audit, report as “client checks are not security; verify backend”.\n\nFix:\n\n* Add/confirm server-side authorization checks.\n* Keep frontend gating only as convenience.\n\nNotes:\n\n* This is a general web app security property; React cannot protect server resources by itself.\n\n---\n\n### REACT-NET-001: Prevent data exfiltration and credential leakage via dynamic outbound requests\n\nSeverity: Medium to High\n\nRequired:\n\n* MUST avoid making authenticated requests to attacker-controlled origins.\n* SHOULD avoid allowing user input to control request destination (scheme/host/port).\n* SHOULD centralize network clients (fetch/axios) with:\n\n  * fixed `baseURL` (or strict allowlist),\n  * strict handling of redirects,\n  * explicit `credentials` usage.\n\nInsecure patterns:\n\n* `fetch(userProvidedUrl, { credentials: 'include' })`\n* `axios.create({ baseURL: userProvidedBase })`\n* “URL fetch/preview” features in the client that hit arbitrary domains with sensitive headers.\n\nDetection hints:\n\n* Search for `fetch(` / `axios(` where the first argument or `baseURL` is derived from:\n\n  * query params, localStorage, API responses, postMessage\n* Search for `credentials: 'include'`, `withCredentials: true`.\n\nFix:\n\n* Enforce destination allowlists; disallow cross-origin requests unless explicitly required.\n* Strip credentials/Authorization headers for any non-allowlisted destination.\n\nNotes:\n\n* Even if the browser limits some cross-origin behavior, leaking tokens/headers to untrusted endpoints is still a common failure mode.\n\n---\n\n### REACT-REDIRECT-001: Prevent open redirects and untrusted navigation\n\nSeverity: Medium\n\nRequired:\n\n* MUST validate redirect/navigation targets derived from untrusted input (`next`, `returnTo`, `redirect`).\n* SHOULD only allow same-site relative paths, or a strict allowlist of trusted origins for absolute URLs.\n\nInsecure patterns:\n\n* `window.location.href = new URLSearchParams(location.search).get('next')`\n* `navigate(next)` where `next` comes from query params.\n\nDetection hints:\n\n* Search for: `next`, `returnTo`, `redirect`, `window.location`, `navigate(`\n* Trace origin of the redirect target.\n\nFix:\n\n* Only allow relative paths (`/^\\/[^\\s]*$/`) or allowlisted origins.\n* Fall back to a safe default (e.g., `/`) when invalid.\n\nNotes:\n\n* Open redirects are frequently used in phishing and can undermine SSO/OAuth flows.\n\n---\n\n### REACT-SW-001: Service workers are high-privilege; require HTTPS and safe caching/update rules\n\nSeverity: Medium\n\nRequired:\n\n* MUST serve service workers over HTTPS (except `localhost` dev), and deploy only in secure contexts.\n* MUST avoid caching sensitive authenticated API responses unless explicitly designed and threat-modeled.\n* SHOULD implement safe update strategy (prompt reload, versioned caches, remove old caches on activate).\n\nInsecure patterns:\n\n* Registering a service worker for an authenticated app and caching “everything” indiscriminately.\n* Long-lived caches containing PII or user-specific content shared across accounts.\n\nDetection hints:\n\n* Search for:\n\n  * `navigator.serviceWorker.register`\n  * `workbox`, `precacheAndRoute`, custom `fetch` handlers\n* Inspect caching patterns (`caches.open`, `cache.put`, `respondWith`).\n\nFix:\n\n* Restrict caching to static assets only (JS/CSS/images) unless you have a designed offline model.\n* Ensure cache keys are user-scoped if user-specific data must be cached.\n* Provide a clear update mechanism.\n\nNotes:\n\n* MDN notes service workers require HTTPS for security reasons and act like a proxy for requests/responses. ([MDN Web Docs][10])\n* “Secure contexts” exist to prevent MITM attackers from accessing powerful APIs; service workers are an example of such a powerful feature. ([MDN Web Docs][18])\n\n---\n\n### REACT-HEADERS-001: Ensure essential security headers are set for the React app shell (app or edge)\n\nSeverity: Medium\n\nRequired (typical SPA served from an origin):\n\n* SHOULD set:\n\n  * CSP (`Content-Security-Policy`)\n  * `X-Content-Type-Options: nosniff`\n  * Clickjacking protection (`frame-ancestors` in CSP and/or `X-Frame-Options`)\n  * `Referrer-Policy`\n  * `Permissions-Policy` as appropriate\n* MUST ensure these are set somewhere (CDN/edge/server), even if not in repo.\n\nInsecure patterns:\n\n* No security headers anywhere (app or edge).\n* CSP missing on apps that render untrusted content or use third-party scripts.\n\nDetection hints:\n\n* Check server/CDN config in repo (nginx, Cloudflare, Vercel config, etc.).\n* If absent, flag as “verify at runtime/edge”.\n\nFix:\n\n* Set headers centrally at the edge.\n* Keep CSP realistic and iterative (report-only → enforce).\n\nNotes:\n\n* MDN clickjacking guidance discusses defenses including `X-Frame-Options` and CSP `frame-ancestors`. ([MDN Web Docs][8])\n* OWASP CSP guidance explains delivery via response headers and recommends headers as the preferred mechanism. ([OWASP Cheat Sheet Series][2])\n\n---\n\n### REACT-POSTMSG-001: `postMessage` must validate origin and treat payload as untrusted data\n\nSeverity: Medium to High (depends on what messages can do)\n\nRequired:\n\n* MUST specify exact `targetOrigin` when sending messages (not `*`) unless there is a strict reason.\n* MUST validate `event.origin` on receipt and validate message shape.\n* MUST NOT evaluate message data as code or insert it into the DOM as HTML.\n\nInsecure patterns:\n\n* `window.postMessage(data, '*')` to unknown targets.\n* Receiving:\n\n  * `window.addEventListener('message', (e) => { eval(e.data) })`\n  * `element.innerHTML = e.data`\n\nDetection hints:\n\n* Search: `postMessage(`, `addEventListener('message'`\n* Check for origin checks and safe handling.\n\nFix:\n\n* Add strict origin allowlists and schema validation (e.g., zod).\n* Treat message payload strictly as data; render safely via React.\n\nNotes:\n\n* OWASP HTML5 guidance recommends specifying expected origin for `postMessage`, checking sender origin, validating data, and avoiding eval/innerHTML with message content. ([OWASP Cheat Sheet Series][4])\n\n---\n\n### REACT-FILE-001: File uploads and previews must not create client-side active content vulnerabilities\n\nSeverity: Medium (can be High if stored-XSS possible)\n\nRequired:\n\n* MUST treat user-uploaded files and previews as potentially malicious.\n* MUST NOT render uploaded HTML/SVG/other active content inline unless sanitized and explicitly required.\n* SHOULD validate file types client-side for UX, but MUST rely on server-side validation for security.\n\nInsecure patterns:\n\n* Rendering user-uploaded HTML as content.\n* Inline rendering of untrusted SVG/HTML via `dangerouslySetInnerHTML` or `<iframe srcdoc=...>` without sanitization.\n\nDetection hints:\n\n* Search for upload components and preview logic:\n\n  * `input type=\"file\"`, `FileReader`, `URL.createObjectURL`, `<iframe>`, `<object>`, `<embed>`.\n* Trace where uploaded content is later displayed.\n\nFix:\n\n* Restrict accepted types, sanitize where needed, and prefer download/attachment flows for risky types.\n* Ensure server enforces the real policy (type checking, renaming, scanning, storing outside webroot).\n\nNotes:\n\n* OWASP file upload guidance highlights allowlisting extensions, validating file type, generating filenames, limiting size, storing outside webroot, and considering “client-side active content (XSS, CSRF, etc.)” when files are publicly retrievable. ([OWASP Cheat Sheet Series][19])\n\n---\n\n### REACT-SUPPLY-001: Dependency and supply-chain hygiene (frontend + build tooling)\n\nSeverity: Low\n\nRequired:\n\n* MUST use a lockfile and enforce reproducible installs in CI.\n* SHOULD regularly audit dependencies and respond quickly to advisories for:\n\n  * React, react-dom, router libs, build tooling (Vite/Webpack), sanitizers, auth libs, etc.\n* SHOULD reduce exposure to install-time script attacks and typosquatting risk.\n\nAudit focus:\n\n* CI should use `npm ci` (or Yarn frozen lockfile / pnpm equivalent) to prevent drift.\n* Use vulnerability scanning (`npm audit`, GitHub Dependabot/alerts, etc.).\n\nInsecure patterns:\n\n* No lockfile or lockfile ignored in CI.\n* `npm install` in CI producing non-reproducible builds.\n* Unpinned or unreviewed high-risk deps; sudden major updates without review.\n* Blindly running install scripts from third-party packages.\n\nDetection hints:\n\n* Check for lockfiles: `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`.\n* Check CI scripts for `npm install` vs `npm ci`.\n* Search for `postinstall` scripts and suspicious build steps.\n\nFix:\n\n* Use lockfile and enforce it in CI (e.g., `npm ci`).\n* Run audits regularly; pin/upgrade responsibly.\n* Consider restricting install scripts where feasible.\n\nNotes:\n\n* npm docs describe `npm audit` as submitting the project dependency tree to the registry to receive a report of known vulnerabilities and (optionally) applying remediations via `npm audit fix`, while noting some vulns require manual review. ([npm Docs][20])\n* npm docs describe `npm ci` as intended for automated/CI environments, requiring an existing lockfile and failing if `package.json` and lockfile do not match. ([npm Docs][21])\n* OWASP NPM security guidance recommends enforcing the lockfile and explicitly calls out `npm ci` / `yarn install --frozen-lockfile` to abort on inconsistencies, and highlights the risk of install-time scripts and the option to use `--ignore-scripts` to reduce attack surface. ([OWASP Cheat Sheet Series][22])\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* Raw HTML / XSS escape hatches:\n\n  * `dangerouslySetInnerHTML`, `__html:`\n  * Markdown HTML passthrough flags: `rehype-raw`, `allowDangerousHtml`, `sanitize: false`\n* DOM XSS sinks:\n\n  * `innerHTML`, `outerHTML`, `insertAdjacentHTML`, `document.write`, `DOMParser`, `createContextualFragment`\n* Dangerous JS execution:\n\n  * `eval(`, `new Function(`, `setTimeout(\"`, `setInterval(\"`\n* Untrusted URL injection / navigation:\n\n  * `href={` / `src={` with untrusted values\n  * `window.location`, `location.href`, `window.open`, `navigate(`\n  * Query params: `next`, `returnTo`, `redirect`\n* Token/session risk:\n\n  * `localStorage.setItem`, `sessionStorage.setItem`, `getItem(` with `token`, `jwt`, `refresh`\n* Cookie/CSRF coupling:\n\n  * `credentials: 'include'`, `withCredentials: true` on state-changing requests without CSRF headers\n* Third-party scripts:\n\n  * `<script src=...>` in `public/index.html`\n  * Tag manager snippets and dynamic script insertion\n* Service workers:\n\n  * `navigator.serviceWorker.register`, Workbox usage, custom `fetch` handlers\n* postMessage:\n\n  * `postMessage(` with `*`, missing `event.origin` checks\n* Supply chain:\n\n  * Missing lockfile, CI uses `npm install`, no audit step, risky postinstall scripts\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (React escape hatch vs DOM sink vs navigation vs storage)\n* protective controls present (sanitization, allowlists, CSP/Trusted Types, CSRF tokens, headers, governance)\n\n---\n\n## 6) Sources (accessed 2026-01-26)\n\nPrimary React documentation:\n\n* React 19 stable announcement — `https://react.dev/blog/2024/12/05/react-19` ([React][23])\n* React DOM docs: `dangerouslySetInnerHTML` warning — `https://react.dev/reference/react-dom/components/common#dangerouslysetting-the-inner-html` ([React][12])\n* React (legacy) JSX escaping statement — `https://legacy.reactjs.org/docs/introducing-jsx.html` ([React][14])\n\nOWASP Cheat Sheet Series:\n\n* Cross Site Scripting Prevention (framework escape hatches; React `dangerouslySetInnerHTML`; URL validation notes) — `https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][9])\n* Content Security Policy — `https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][2])\n* Cross-Site Request Forgery Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][6])\n* HTML5 Security (Web Storage, postMessage, tabnabbing, sandboxed frames) — `https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][4])\n* Third Party JavaScript Management — `https://cheatsheetseries.owasp.org/cheatsheets/Third_Party_Javascript_Management_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][5])\n* File Upload — `https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][19])\n* NPM Security best practices — `https://cheatsheetseries.owasp.org/cheatsheets/NPM_Security_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][22])\n\nBrowser / platform references (MDN, W3C):\n\n* Trusted Types API — `https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API` ([MDN Web Docs][3])\n* W3C Trusted Types spec — `https://www.w3.org/TR/trusted-types/` ([W3C][15])\n* Subresource Integrity — `https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity` ([MDN Web Docs][7])\n* Clickjacking defenses overview — `https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/Clickjacking` ([MDN Web Docs][8])\n* Using Service Workers (HTTPS requirement; proxy-like behavior) — `https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers` ([MDN Web Docs][10])\n* Secure contexts (powerful APIs restricted to HTTPS) — `https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Secure_Contexts` ([MDN Web Docs][18])\n* Link `rel` values (noopener/noreferrer) — `https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel` ([MDN Web Docs][17])\n\nBuild tooling / env exposure references:\n\n* Create React App env variables warning — `https://create-react-app.dev/docs/adding-custom-environment-variables/` ([create-react-app.dev][1])\n* Vite env variables security notes — `https://vite.dev/guide/env-and-mode` ([vitejs][11])\n\nAuth/token storage guidance:\n\n* OAuth 2.0 for Browser-Based Apps (token storage discussion) — `https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps` ([IETF Datatracker][16])\n\nDependency tooling references:\n\n* npm audit docs — `https://docs.npmjs.com/cli/v10/commands/npm-audit/` ([npm Docs][20])\n* npm ci docs — `https://docs.npmjs.com/cli/v10/commands/npm-ci/` ([npm Docs][21])\n\nSanitizer reference:\n\n* DOMPurify — `https://github.com/cure53/DOMPurify` ([GitHub][13])\n\n[1]: https://create-react-app.dev/docs/adding-custom-environment-variables/ \"Adding Custom Environment Variables | Create React App\"\n[2]: https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html \"Content Security Policy - OWASP Cheat Sheet Series\"\n[3]: https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API \"Trusted Types API - Web APIs | MDN\"\n[4]: https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html \"HTML5 Security - OWASP Cheat Sheet Series\"\n[5]: https://cheatsheetseries.owasp.org/cheatsheets/Third_Party_Javascript_Management_Cheat_Sheet.html \"Third Party Javascript Management - OWASP Cheat Sheet Series\"\n[6]: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html \"Cross-Site Request Forgery Prevention - OWASP Cheat Sheet Series\"\n[7]: https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity \"Subresource Integrity - Security | MDN\"\n[8]: https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/Clickjacking \"Clickjacking - Security | MDN\"\n[9]: https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html \"Cross Site Scripting Prevention - OWASP Cheat Sheet Series\"\n[10]: https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers \"Using Service Workers - Web APIs | MDN\"\n[11]: https://vite.dev/guide/env-and-mode \"Env Variables and Modes | Vite\"\n[12]: https://react.dev/reference/react-dom/components/common \"Common components (e.g. <div>) – React\"\n[13]: https://github.com/cure53/DOMPurify \"GitHub - cure53/DOMPurify: DOMPurify - a DOM-only, super-fast, uber-tolerant XSS sanitizer for HTML, MathML and SVG. DOMPurify works with a secure default, but offers a lot of configurability and hooks. Demo:\"\n[14]: https://legacy.reactjs.org/docs/introducing-jsx.html \"Introducing JSX – React\"\n[15]: https://www.w3.org/TR/trusted-types/ \"Trusted Types\"\n[16]: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps \"\n\n                draft-ietf-oauth-browser-based-apps-26\n\n        \"\n[17]: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel \"HTML attribute: rel - HTML | MDN\"\n[18]: https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Secure_Contexts \"Secure contexts - Security | MDN\"\n[19]: https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html \"File Upload - OWASP Cheat Sheet Series\"\n[20]: https://docs.npmjs.com/cli/v10/commands/npm-audit \"npm-audit | npm Docs\"\n[21]: https://docs.npmjs.com/cli/v10/commands/npm-ci \"npm-ci | npm Docs\"\n[22]: https://cheatsheetseries.owasp.org/cheatsheets/NPM_Security_Cheat_Sheet.html \"NPM Security - OWASP Cheat Sheet Series\"\n[23]: https://react.dev/blog/2024/12/05/react-19 \"React v19 – React\"\n","core/skills/builtin/security-best-practices/references/javascript-typescript-vue-web-frontend-security.md":"# Vue.js Web Security Spec (Vue 3.x, TypeScript/JavaScript, common tooling: Vite)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new Vue code.\n2. **Security review / vulnerability hunting** in existing Vue code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session cookies, auth tokens).\n* MUST NOT “fix” security by disabling protections (e.g., weakening CSP, turning on unsafe template compilation, using `v-html` as a shortcut, bypassing backend auth, or “just store the token in localStorage”).\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and configuration values that justify the claim.\n* MUST treat uncertainty honestly: if a protection might exist at the edge (CDN, reverse proxy, WAF, server headers), report it as “not visible in repo; verify runtime/infra config”.\n* MUST remember the frontend trust model: **any code shipped to browsers is attacker-readable and attacker-modifiable**. Secrets and “security enforcement” cannot rely on frontend-only logic.\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new Vue code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default framework features and proven libraries over custom security code.\n* MUST avoid introducing new risky sinks (runtime template compilation, `v-html` / `innerHTML`, unsafe URL navigation, dynamic script injection, etc.). ([Vue.js][1])\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a Vue repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. Build/deploy entrypoints and hosting config (Docker, CI, static hosting, SSR server).\n2. Secrets exposure (env usage, `.env*`, hard-coded keys). ([vitejs][2])\n3. XSS surface: templates, `v-html` / `innerHTML`, URL/style injection, DOM APIs. ([Vue.js][1])\n4. Auth/session handling in the browser (token storage, credentialed requests, CSRF integration). ([Vue.js][1])\n5. Routing/navigation (open redirects, “return_to/next”, unsafe external navigation). ([Vue.js][1])\n6. Third-party scripts and content (CDN assets, analytics, widgets, iframes). ([Vue.js][1])\n7. Security headers and browser hardening expectations (CSP, clickjacking). ([Vue.js][1])\n8. SSR-specific concerns (state serialization, template boundaries) when applicable. ([Vue.js][1])\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nIn a Vue app, untrusted input includes (non-exhaustive):\n\n* Anything from APIs: `fetch`, `axios`, GraphQL responses, webhooks, third-party SDKs.\n* Router-controlled data: `route.params`, `route.query`, `route.hash`, and anything derived from `window.location`.\n* User-controlled persisted content: DB-backed content displayed in the UI (comments, profiles, CMS content).\n* Browser-controlled storage: `localStorage`, `sessionStorage`, `IndexedDB`.\n* Cross-window messages: `postMessage` inputs.\n* Anything that can be influenced by an attacker through DOM clobbering or injected HTML (especially if Vue is mounted onto non-sterile DOM). ([Vue.js][1])\n\n### 2.2 State-changing action (frontend perspective)\n\nAn action is state-changing if it can:\n\n* Create/update/delete data via API calls.\n* Change authentication/session state (login, logout, refresh token).\n* Trigger privileged operations (payments, admin actions).\n* Cause side effects (sending emails, triggering webhooks, changing account settings).\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + component/function + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common Vue/front-end misconfigurations.\n\n* MUST ship a **production build** (not a development build or dev server). ([Vue.js][3])\n* MUST NOT ship secrets in frontend bundles; treat all client-exposed env variables as public. ([vitejs][2])\n* MUST NOT render non-trusted templates or allow user-provided Vue templates (equivalent to arbitrary JS execution). ([Vue.js][1])\n* SHOULD avoid raw HTML injection (`v-html`, `innerHTML`) unless content is trusted or strongly sandboxed. ([Vue.js][1])\n* SHOULD deploy baseline security headers (especially CSP and clickjacking defenses) at the server/CDN layer. ([OWASP Cheat Sheet Series][4])\n* SHOULD use safe auth patterns (prefer HttpOnly cookies for session tokens; coordinate with backend on CSRF). ([Vue.js][1])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### VUE-DEPLOY-001: Do not run dev/preview servers in production\n\nSeverity: High\n\nRequired:\n\n* MUST NOT deploy the Vite/Vue dev server (`vite`, `npm run dev`, HMR) as the production server.\n* MUST NOT use `vite preview` as a production server. ([vitejs][5])\n* MUST build (`vite build`) and serve the built assets using a production-grade static server/CDN, or a production SSR server if you are doing SSR. ([vitejs][6])\n\nInsecure patterns:\n\n* Docker/Procfile/systemd running `vite`, `npm run dev`, or `vite preview` as the production entrypoint.\n* Publicly exposed HMR endpoints.\n\nDetection hints:\n\n* Search: `vite`, `npm run dev`, `pnpm dev`, `yarn dev`, `vite preview`, `vue-cli-service serve`.\n* Check Docker `CMD`, `ENTRYPOINT`, CI deploy scripts, platform config.\n\nFix:\n\n* Build artifacts with `vite build`.\n* Serve `dist/` with hardened hosting (CDN/static server) or integrate into your backend server as static assets.\n\nNotes:\n\n* Using dev/preview servers locally is fine; only flag if it is the production entrypoint.\n\n---\n\n### VUE-DEPLOY-002: Use Vue production builds and keep devtools off in production\n\nSeverity: Medium (High if production devtools/debug hooks are enabled)\n\nRequired:\n\n* If loading Vue from CDN/self-host without a bundler, MUST use the `.prod.js` builds in production. ([Vue.js][3])\n* SHOULD ensure production bundles do not enable Vue devtools in production builds, and SHOULD not intentionally enable production devtools flags. ([Vue.js][7])\n\nInsecure patterns:\n\n* Production includes development build artifacts.\n* Explicitly enabling production devtools/diagnostic hooks.\n\nDetection hints:\n\n* Search HTML for `vue.global.js` / non-`.prod.js` variants when using CDN builds.\n* Search build config for Vue feature flags like `__VUE_PROD_DEVTOOLS__`. ([Vue.js][7])\n\nFix:\n\n* Switch to production build artifacts and ensure compile-time flags are configured for production.\n\n---\n\n### VUE-SECRETS-001: Never ship secrets in frontend code or env variables\n\nSeverity: High (Critical if real credentials are exposed)\n\nRequired:\n\n* MUST treat all frontend code and configuration as public.\n* MUST NOT embed secrets in:\n\n  * source code\n  * `.env` files committed to repo\n  * `import.meta.env.*` variables included in the bundle\n* MUST assume any env var that ends up in the client bundle is attacker-readable. ([vitejs][2])\n\nInsecure patterns:\n\n* `VITE_API_KEY=...` containing a true secret (not just a public identifier).\n* Hard-coded API keys, private tokens, service credentials, signing keys in JS/TS.\n\nDetection hints:\n\n* Search: `VITE_`, `import.meta.env`, `.env`, `.env.production`, `.env.*.local`.\n* Grep for `API_KEY`, `SECRET`, `TOKEN`, `PRIVATE_KEY`, `BEGIN`, `sk-`, `AKIA`, etc.\n\nFix:\n\n* Move secrets to backend/edge functions.\n* Use backend-minted short-lived tokens for the browser when needed.\n\nNotes:\n\n* Vite specifically warns that `.env.*.local` should be gitignored and that `VITE_*` vars end up in the client bundle, so they must not contain sensitive info. ([vitejs][2])\n\n---\n\n### VUE-SECRETS-002: Do not broaden Vite env exposure\n\nSeverity: High\n\nRequired:\n\n* MUST NOT configure Vite to expose all environment variables to the client.\n* SHOULD keep `envPrefix` strict and explicit.\n\nInsecure patterns:\n\n* Setting `envPrefix` to overly broad values (or `''`) to “make env vars work”.\n* Custom scripts that inject server secrets into global variables in HTML at build time.\n\nDetection hints:\n\n* Check `vite.config.*` for `envPrefix`.\n* Look for `define: { 'process.env': ... }` or manual injection into `window.__CONFIG__`.\n\nFix:\n\n* Keep secrets server-side.\n* Only expose non-sensitive values intentionally designed to be public.\n\nNotes:\n\n* Vite’s docs explain that only prefixed variables are exposed and that exposed variables land in the client bundle. ([vitejs][2])\n\n---\n\n### VUE-XSS-001: Prefer Vue’s default escaping; avoid raw HTML injection\n\nSeverity: High\n\nRequired:\n\n* MUST rely on Vue’s automatic escaping for text interpolation and attribute binding where possible. ([Vue.js][1])\n* MUST NOT render user-provided HTML via:\n\n  * `v-html`\n  * `innerHTML` in render functions / JSX\n  * direct DOM APIs (`element.innerHTML`, `insertAdjacentHTML`)\n    unless the HTML is trusted or robustly sanitized and the risk is explicitly accepted. ([Vue.js][1])\n\nInsecure patterns:\n\n* `<div v-html=\"userProvidedHtml\"></div>`\n* `h('div', { innerHTML: userProvidedHtml })`\n* `<div innerHTML={userProvidedHtml}></div>`\n* `el.innerHTML = untrusted`\n\nDetection hints:\n\n* Search: `v-html`, `innerHTML`, `insertAdjacentHTML`, `DOMParser`, `document.write`.\n\nFix:\n\n* Render untrusted content as text (interpolation).\n* If HTML rendering is required (e.g., Markdown), sanitize with a well-maintained HTML sanitizer and apply defense-in-depth (CSP, Trusted Types). ([Vue.js][1])\n\nNotes:\n\n* Vue’s docs explicitly warn that user-provided HTML is never “100% safe” unless sandboxed or strictly self-only exposure. ([Vue.js][1])\n\n---\n\n### VUE-XSS-002: Never use non-trusted templates (client-side template/code injection)\n\nSeverity: Critical\n\nRequired:\n\n* MUST NOT use non-trusted content as a Vue component template.\n* MUST treat “user can write a Vue template” as “user can execute arbitrary JavaScript in your app”, and potentially in SSR contexts too. ([Vue.js][1])\n* SHOULD prefer the runtime-only build (templates compiled at build time) and avoid shipping the runtime compiler unless you have a vetted need.\n\nInsecure patterns:\n\n* `createApp({ template: '<div>' + userProvidedString + '</div>' }).mount(...)`\n* Storing templates in DB and compiling/rendering them in the browser.\n* Admin/CMS features that allow entering Vue template syntax.\n\nDetection hints:\n\n* Search: `template:` where the value is not a static string.\n* Search: `@vue/compiler-dom`, `compile(`, “runtime compiler” build selection, dynamic SFC compilation.\n* Search for “template editor”, “custom template”, “theme HTML” features.\n\nFix:\n\n* Treat templates as code: keep them developer-controlled.\n* If end-user customization is required, use a safe format (restricted Markdown subset) rendered via a sanitizer, or isolate in a sandboxed iframe.\n\n---\n\n### VUE-XSS-003: Do not mount Vue onto DOM that may contain user-provided server-rendered HTML\n\nSeverity: Medium\n\nRequired:\n\n* MUST NOT mount Vue on nodes that may contain server-rendered and user-provided content (because attacker-controlled HTML that is “safe as HTML” may become unsafe as a Vue template). ([Vue.js][1])\n* SHOULD mount Vue into a “sterile” root element and render the app’s DOM from Vue-controlled templates/components.\n\nInsecure patterns:\n\n* Server renders user content into `#app`, then Vue mounts on `#app` and compiles/interprets that DOM as a template.\n* “Sprinkling Vue” on large server-rendered pages that include user-generated content.\n\nDetection hints:\n\n* Check server templates (e.g., Rails/Django/Express templates) for user HTML inserted inside the Vue mount root.\n* Look for `mount('#app')` where `#app` includes server-rendered UGC.\n\nFix:\n\n* Move user-rendered HTML outside the Vue mount root, or render it in a safe way (text/sanitized HTML) from Vue components.\n\n---\n\n### VUE-XSS-004: Prevent URL injection in bindings and navigations\n\nSeverity: High\n\nRequired:\n\n* MUST validate/sanitize any user-influenced URL before binding to navigation sinks (`href`, `src`, `action`, `window.location`, `window.open`, router navigation to external).\n* MUST specifically prevent `javascript:` URL execution in bindings like `<a :href=\"userProvidedUrl\">`. ([Vue.js][1])\n* SHOULD validate protocol and destination (allowlist `https:` and expected hosts; allow `mailto:`/`tel:` only if intended).\n\nInsecure patterns:\n\n* `<iframe :src=\"userProvidedUrl\">`\n* `window.location = route.query.next`\n* `window.open(userProvidedUrl)`\n\nDetection hints:\n\n* Search: `:href=`, `:src=`, `window.location`, `location.href`, `window.open`, `router.push(` with untrusted input.\n* Look for `next`, `return_to`, `redirect` query params.\n\nFix:\n\n* Prefer internal navigation via route names/paths you control.\n* For external URLs: parse with `new URL(...)`, allowlist protocol/host, reject `javascript:` and other dangerous schemes.\n* Sanitize and validate on the backend before storing user URLs (Vue docs explicitly recommend backend sanitization). ([Vue.js][1])\n\n---\n\n### VUE-XSS-005: Prevent style/CSS injection and UI redress\n\nSeverity: Low\n\nRequired:\n\n* MUST NOT bind attacker-controlled CSS strings broadly (e.g., `:style=\"userProvidedStyles\"`).\n* SHOULD use Vue’s style object syntax and only allow safe, specific properties if user customization is needed. ([Vue.js][1])\n* SHOULD isolate “user can control layout/CSS” features inside sandboxed iframes.\n\nInsecure patterns:\n\n* `:style=\"userProvidedStyles\"` where styles are attacker-controlled.\n* Rendering user-provided `<style>` content (even if Vue blocks some patterns, don’t try to work around it).\n\nDetection hints:\n\n* Search: `:style=\"` bound to non-constant variables that originate from API/user content.\n* Search for “custom CSS”, “theme editor”, “profile CSS”.\n\nFix:\n\n* Allowlist properties and values; avoid raw style strings.\n* Use sandboxed iframes for rich user customization.\n\n---\n\n### VUE-XSS-006: Never bind user-provided JavaScript into event handler attributes\n\nSeverity: Critical\n\nRequired:\n\n* MUST NOT bind attacker-provided strings into event handler attributes (e.g., `onclick`, `onfocus`, etc.).\n* MUST treat “user-provided JS” as unsafe unless sandboxed and self-only exposure is guaranteed. ([Vue.js][1])\n\nInsecure patterns:\n\n* `<div :onclick=\"userProvidedString\">`\n* `<a :onmouseenter=\"userProvidedString\">`\n\nDetection hints:\n\n* Search: `:on` followed by event attribute names (`:onclick`, `:onload`, etc.).\n* Search for `setAttribute('on` patterns.\n\nFix:\n\n* Use real event listeners with developer-controlled handlers.\n* If you truly need user scripting, isolate it (sandboxed iframe + strict boundaries).\n\n---\n\n### VUE-ROUTER-001: Do not treat client-side route guards as authorization\n\nSeverity: High\n\nRequired:\n\n* MUST NOT rely on Vue Router guards, UI hiding, or client-side checks to enforce authorization.\n* MUST enforce authorization on the backend for every privileged action and sensitive data response. ([OWASP Cheat Sheet Series][8])\n\nInsecure patterns:\n\n* “Admin route is protected because `beforeEach` checks `user.isAdmin`.”\n* Sensitive API endpoints that assume “the frontend won’t call this unless allowed.”\n\nDetection hints:\n\n* Search `router.beforeEach` for role-based gating and see if the backend is also enforcing.\n* Look for “security by route meta” patterns (`meta.requiresAdmin`) with no server corroboration.\n\nFix:\n\n* Keep route guards as UX only (reduce accidental access), but enforce real checks server-side.\n\n---\n\n### VUE-ROUTER-002: Prevent open redirects and unsafe “return_to/next” handling\n\nSeverity: Low\n\nRequired:\n\n* MUST validate redirect destinations derived from untrusted input (`next`, `return_to`, `redirect`).\n* SHOULD allow only same-site relative paths or an explicit allowlist of destinations.\n* MUST NOT allow non `http` / `https` protos (such as `javascript:`)\n\nInsecure patterns:\n\n* `router.push(route.query.next as string)`\n* `window.location.href = route.query.redirect`\n\nDetection hints:\n\n* Search for `route.query.next`, `route.query.redirect`, `return_to`, `continue`, `callback`.\n* Trace the value into router/window navigation sinks.\n\nFix:\n\n* Allow only relative paths starting with `/` (and reject `//host`, `javascript:`, etc.).\n* Prefer redirecting to named routes you control.\n\nNotes:\n\n* Even Vue’s docs note that sanitized URLs still may not guarantee safe destinations. ([Vue.js][1])\n\n---\n\n### VUE-AUTH-001: Token storage must assume XSS is possible\n\nSeverity: Low\n\nRequired:\n\n* MUST assume any token accessible to JavaScript can be stolen via XSS.\n* SHOULD prefer HttpOnly cookies (set by the backend) for session tokens, combined with CSRF protections where relevant. ([Vue.js][1])\n* SHOULD avoid storing long-lived tokens (especially refresh tokens) in `localStorage`/`sessionStorage`.\n\nInsecure patterns:\n\n* `localStorage.setItem('token', ...)` for long-lived bearer tokens.\n* Storing refresh tokens in JS-accessible storage.\n\nDetection hints:\n\n* Search: `localStorage`, `sessionStorage`, `indexedDB`, `persist`, `pinia-plugin-persistedstate`.\n* Identify whether stored values are auth/session material.\n\nFix:\n\n* Prefer backend-managed sessions via HttpOnly cookies.\n* If bearer tokens are unavoidable, keep them short-lived, stored in memory, and rotate frequently; combine with strong XSS mitigations (CSP, Trusted Types, strict sanitization). ([OWASP Cheat Sheet Series][4])\n\n---\n\n### VUE-CSRF-001: Coordinate with the backend for CSRF when using cookies\n\nSeverity: High (for cookie-authenticated state-changing requests)\n\nNOTE: If the application is not using cookie based authentication (for example if it passes an Authorization header), then CSRF is not a concern\n\nRequired:\n\n* If API requests include cookies (`credentials: 'include'` / `withCredentials: true`) and cookies authenticate the user, MUST include CSRF protections coordinated with the backend (token/header patterns, Origin checks, SameSite cookies as defense-in-depth). ([Vue.js][1])\n* MUST NOT “solve CORS/CSRF errors” by disabling protections on the backend or using `mode: 'no-cors'` on the frontend.\n\nInsecure patterns:\n\n* `fetch(url, { credentials: 'include', method: 'POST', body: ... })` with no CSRF token/header usage anywhere.\n* Enabling cross-origin credentialed requests without strict origin allowlists (backend-side).\n\nDetection hints:\n\n* Search: `credentials: 'include'`, `withCredentials`, `xsrf`, `csrf`, `X-CSRF-Token`, `X-XSRF-TOKEN`.\n* Look at API wrapper modules for headers and cookie settings.\n\nFix:\n\n* Implement backend-issued CSRF tokens and require them on state-changing requests.\n* Keep cookies `SameSite=Lax/Strict` where compatible and verify Origin/Referer where appropriate (backend-driven). ([OWASP Cheat Sheet Series][9])\n\nNotes:\n\n* Vue’s docs explicitly say CSRF is primarily backend-addressed but recommends coordinating on CSRF token submission. ([Vue.js][1])\n\n---\n\n### VUE-HTTP-001: Do not put secrets in URLs; avoid leaking sensitive data in navigation/logs\n\nSeverity: Medium\n\nRequired:\n\n* MUST NOT place tokens/secrets in query strings or fragments (they leak via logs, referrers, browser history).\n* SHOULD avoid logging sensitive values to console in production.\n\nInsecure patterns:\n\n* `/?token=...`, `/#access_token=...` used beyond short-lived OAuth handoff.\n* `console.log(userSession)` that includes tokens/PII.\n\nDetection hints:\n\n* Search for `token=` in router parsing, auth callback handlers, and analytics logs.\n* Search for `console.log(` around auth code.\n\nFix:\n\n* Use Authorization headers or HttpOnly cookies.\n* Scrub logs; gate debug logs behind dev-only checks.\n\n---\n\n### VUE-HEADERS-001: Require security headers at the deployment layer\n\nSeverity: Medium\n\nRequired:\n\n* SHOULD deploy a CSP (`Content-Security-Policy`) suitable for your Vue app.\n* SHOULD deploy clickjacking defenses (CSP `frame-ancestors` and/or `X-Frame-Options`) unless intentional embedding is required.\n* SHOULD deploy `X-Content-Type-Options: nosniff`, plus other headers as appropriate (Referrer-Policy, Permissions-Policy). ([OWASP Cheat Sheet Series][4])\n\nInsecure patterns:\n\n* No evidence of headers in server/CDN config for an app with UGC or rich HTML rendering.\n* CSP includes `unsafe-inline`/`unsafe-eval` without strong justification.\n\nDetection hints:\n\n* Look for hosting config: nginx, Netlify/Vercel headers config, CloudFront/Cloudflare rules.\n* If absent in repo, flag as “verify at edge”.\n\nFix:\n\n* Set headers at the edge or in the server. Start with a conservative CSP and tighten.\n\n---\n\n### VUE-CSP-001: Use Trusted Types and DOM XSS hardening when feasible\n\nSeverity: Low\n\nRequired:\n\n* For apps with significant DOM injection surface (rich text, plugins, `v-html`), SHOULD consider enabling Trusted Types to reduce DOM XSS risk. ([web.dev][10])\n* SHOULD treat Trusted Types as defense-in-depth, not a replacement for sanitization.\n\nInsecure patterns:\n\n* Frequent use of `innerHTML`/`v-html` without sanitization or CSP hardening.\n\nDetection hints:\n\n* Search: `v-html`, `innerHTML`, `insertAdjacentHTML`.\n* Check CSP for `require-trusted-types-for 'script'` usage (if headers are in repo).\n\nFix:\n\n* Reduce/centralize HTML injection, sanitize inputs, and add Trusted Types policies where appropriate.\n\n---\n\n### VUE-THIRDPARTY-001: Avoid dynamic third-party script injection; prefer static, vetted loading\n\nSeverity: Low\n\nRequired:\n\n* MUST NOT inject `<script src=\"...\">` where the URL is user-controlled.\n* SHOULD treat third-party widgets/analytics as supply-chain risk; load only from vetted, pinned sources.\n\nInsecure patterns:\n\n* `const s=document.createElement('script'); s.src = userProvidedUrl; ...`\n* “Plugin marketplace” that loads arbitrary remote scripts.\n\nDetection hints:\n\n* Search: `createElement('script')`, `.src =`, `appendChild(script)`.\n* Search for “loadExternalScript”, “injectScript”, “cdnUrl”.\n\nFix:\n\n* Bundle dependencies, or allowlist strict origins and enforce integrity (see SRI rule).\n* Consider sandboxed iframes for untrusted third-party UI.\n\n---\n\n### VUE-SRI-001: Use Subresource Integrity for CDN-hosted scripts/styles\n\nSeverity: Low\n\nRequired:\n\n* If loading scripts/styles from a CDN, SHOULD use Subresource Integrity (`integrity` attribute) with appropriate `crossorigin` configuration. ([MDN Web Docs][11])\n* SHOULD prefer self-hosting or bundling over runtime CDN dependencies for security-critical code.\n\nInsecure patterns:\n\n* `<script src=\"https://cdn.example/...\">` with no `integrity`.\n* Remote script URLs that can change content without version pinning.\n\nDetection hints:\n\n* Search `index.html` and server templates for `https://` script/style tags.\n* Check for `integrity=`.\n\nFix:\n\n* Add SRI hashes (and pin versions), or bundle assets with your build.\n\n---\n\n### VUE-SUPPLY-001: Dependency and patch hygiene is mandatory\n\nSeverity: Low\n\nRequired:\n\n* SHOULD keep Vue and official companion libraries updated; Vue explicitly recommends using latest versions to remain as secure as possible. ([Vue.js][1])\n* MUST respond to security advisories promptly.\n* SHOULD pin dependencies and keep lockfiles committed (to reduce drift in production artifacts).\n\nInsecure patterns:\n\n* Outdated major versions with known CVEs.\n* No lockfile in repo; wide semver ranges for critical deps.\n* Ignoring advisories for template/rendering/compiler packages.\n\nDetection hints:\n\n* Inspect `package.json`, lockfiles, CI install commands.\n* Search for `npm audit` disabled, “ignore vulnerabilities” scripts.\n\nFix:\n\n* Upgrade dependencies and add regression tests around the impacted behavior.\n* Add dependency scanning in CI.\n\n---\n\n### VUE-SSR-001: SSR adds additional trust boundaries; treat state injection as XSS-sensitive\n\nSeverity: Medium\n\nRequired:\n\n* When using SSR, MUST treat anything injected into the HTML document (initial state, serialized data, inline scripts) as XSS-sensitive.\n* MUST keep the “trusted templates only” rule even stricter, because unsafe templates can lead to server-side execution during rendering. ([Vue.js][1])\n* SHOULD follow Vue SSR documentation and best practices for SSR security. ([Vue.js][1])\n\nInsecure patterns:\n\n* Concatenating untrusted strings into SSR templates.\n* Injecting JSON into `<script>` blocks without robust escaping/serialization controls.\n\nDetection hints:\n\n* Search server code for `__INITIAL_STATE__`, `window.__*STATE__`, template concatenation, and SSR render pipelines.\n* Trace untrusted data into those sinks.\n\nFix:\n\n* Use safe serialization patterns recommended by your SSR stack.\n* Avoid rendering untrusted HTML; sanitize or isolate.\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* Dev/preview servers in production:\n\n  * `npm run dev`, `vite`, `vite preview`, `vue-cli-service serve` ([vitejs][5])\n* Secrets exposure:\n\n  * `.env`, `.env.production`, `.env.*.local`, `VITE_`, `import.meta.env`, hard-coded `API_KEY` / `SECRET` ([vitejs][2])\n* XSS sinks:\n\n  * `v-html`, `innerHTML`, `insertAdjacentHTML`, `DOMParser`, `document.write` ([Vue.js][1])\n* Client-side template injection:\n\n  * `template:` concatenation, `compile(`, runtime compiler usage, mounting on non-sterile DOM ([Vue.js][1])\n* URL injection / open redirects:\n\n  * `:href=\"...\"` / `:src=\"...\"` from user data\n  * `javascript:` occurrences\n  * `route.query.next` / `redirect` / `return_to` flowing into `router.push` or `window.location` ([Vue.js][1])\n* Style injection:\n\n  * `:style=\"userProvidedStyles\"` or user-driven theme CSS ([Vue.js][1])\n* Token storage:\n\n  * `localStorage.setItem('token'...)`, persisted auth stores, refresh tokens in JS-accessible storage\n* CSRF integration red flags:\n\n  * `credentials: 'include'` / `withCredentials: true` without any CSRF header/token handling ([Vue.js][1])\n* Third-party scripts:\n\n  * dynamic script injection (`createElement('script')`), CDN scripts without SRI ([MDN Web Docs][11])\n* External links security:\n\n  * `target=\"_blank\"` without `rel=\"noopener\"`/`noreferrer` (still recommended for legacy and explicitness) ([MDN Web Docs][12])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (HTML/DOM insertion, template compilation, URL navigation, style injection, script injection)\n* protective controls present (sanitization, allowlists, CSP/Trusted Types, backend validation)\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary Vue documentation:\n\n* Vue Docs: Security — `https://vuejs.org/guide/best-practices/security` ([Vue.js][1])\n* Vue Docs: Template Syntax (security warning about in-DOM templates) — `https://vuejs.org/guide/essentials/template-syntax` ([Vue.js][13])\n* Vue Docs: Production Deployment — `https://vuejs.org/guide/best-practices/production-deployment` ([Vue.js][3])\n* Vue Docs: Feature Flags — `https://link.vuejs.org/feature-flags` ([Vue.js][7])\n\nVite documentation (common Vue tooling):\n\n* Vite Docs: Env Variables and Modes (VITE_* exposure + security notes) — `https://vite.dev/guide/env-and-mode` ([vitejs][2])\n* Vite Docs: CLI (`vite preview` not designed for production) — `https://vite.dev/guide/cli` ([vitejs][5])\n* Vite Docs: Server Options (`server.host` can listen on public addresses) — `https://vite.dev/config/server-options` ([vitejs][14])\n\nOWASP and web platform hardening references:\n\n* OWASP Cheat Sheet Series: XSS Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html` ([Vue.js][1])\n* OWASP Cheat Sheet Series: CSRF Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][9])\n* OWASP Cheat Sheet Series: Authorization — `https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][8])\n* OWASP Cheat Sheet Series: HTTP Headers — `https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][4])\n* HTML5 Security Cheat Sheet (referenced by Vue) — `https://html5sec.org/` ([Vue.js][1])\n\nBrowser/platform references:\n\n* MDN: `rel=\"noopener\"` — `https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/noopener` ([MDN Web Docs][12])\n* MDN: Subresource Integrity — `https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity` ([MDN Web Docs][11])\n* web.dev: Trusted Types — `https://web.dev/trusted-types/` ([web.dev][10])\n\n[1]: https://vuejs.org/guide/best-practices/security \"https://vuejs.org/guide/best-practices/security\"\n[2]: https://vite.dev/guide/env-and-mode \"https://vite.dev/guide/env-and-mode\"\n[3]: https://vuejs.org/guide/best-practices/production-deployment \"https://vuejs.org/guide/best-practices/production-deployment\"\n[4]: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html\"\n[5]: https://vite.dev/guide/cli \"https://vite.dev/guide/cli\"\n[6]: https://vite.dev/guide/build \"https://vite.dev/guide/build\"\n[7]: https://vuejs.org/guide/best-practices/production-deployment?utm_source=chatgpt.com \"Production Deployment\"\n[8]: https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html\"\n[9]: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html\"\n[10]: https://web.dev/articles/trusted-types \"https://web.dev/articles/trusted-types\"\n[11]: https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity?utm_source=chatgpt.com \"Subresource Integrity - Security - MDN Web Docs\"\n[12]: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/noopener \"https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/noopener\"\n[13]: https://vuejs.org/guide/essentials/template-syntax \"Template Syntax | Vue.js\"\n[14]: https://vite.dev/config/server-options \"https://vite.dev/config/server-options\"\n","core/skills/builtin/security-best-practices/references/python-django-web-server-security.md":"# Django (Python) Web Security Spec (Django 6.0.x, Python 3.x)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new Django code.\n2. **Security review / vulnerability hunting** in existing Django code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session cookies, `SECRET_KEY`, `SECRET_KEY_FALLBACKS`, database passwords).\n* MUST NOT “fix” security by disabling protections (e.g., removing `CsrfViewMiddleware`, sprinkling `@csrf_exempt`, loosening `ALLOWED_HOSTS` to `['*']`, disabling `SecurityMiddleware`, disabling template auto-escaping, disabling permission checks).\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and concrete configuration values that justify the claim.\n* MUST treat uncertainty honestly: if a protection might exist in infrastructure (reverse proxy, WAF, CDN, ingress controller), report it as “not visible in app code; verify at runtime / edge config”.\n* MUST keep fixes compatible with Django’s intended security model: prefer Django’s built-ins (middleware, auth, forms, ORM) over custom security logic whenever possible. Django’s deployment checklist and system checks are part of the intended model. ([Django Project][1])\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new Django code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default Django APIs and proven libraries over custom security code.\n* MUST avoid introducing new risky sinks (dynamic template rendering from untrusted strings, unsafe redirects, unsafe file serving, shell execution, raw SQL string formatting, SSRF-capable URL fetchers from untrusted input).\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a Django repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. Deployment entrypoints (ASGI/WSGI), Dockerfiles, Procfiles, systemd units, platform manifests.\n2. `settings.py` and environment-specific settings modules.\n3. Middleware ordering and enabled protections.\n4. Authn/authz (login, session management, permissions, admin).\n5. CSRF protections and state-changing endpoints.\n6. Templates and XSS.\n7. File handling (uploads/downloads/static/media) and path traversal.\n8. Injection classes (SQL, command execution, unsafe deserialization).\n9. Outbound requests (SSRF).\n10. Redirect handling (open redirects) + CORS + security headers (CSP, HSTS, etc.).\n11. Dependency/pinning and patch posture.\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nExamples include:\n\n* `request.GET`, `request.POST`, `request.FILES`\n* `request.body`, JSON bodies (e.g., `json.loads(request.body)`), DRF `request.data`\n* URL path parameters (e.g., `<int:id>`, `<slug:...>`)\n* `request.headers` / `request.META` (including `HTTP_HOST`, `HTTP_ORIGIN`, `HTTP_REFERER`, `HTTP_X_FORWARDED_*`)\n* `request.COOKIES`\n* Any data from external systems (webhooks, third-party APIs, message queues)\n* Any persisted content that originated from users (DB rows, cached content, file uploads)\n\nDjango explicitly emphasizes “never trust user-controlled data” and recommends using forms/validation. ([Django Project][2])\n\n### 2.2 State-changing request\n\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook send), or initiate privileged actions.\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + function/class/view name + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common Django misconfigurations. Django provides a “Deployment checklist” and recommends running `manage.py check --deploy` against production settings. ([Django Project][1])\n\n### 3.1 Settings management pattern (SHOULD)\n\n* SHOULD use environment-based configuration (or a secret manager) so production settings are not hard-coded.\n* MUST treat sensitive settings as confidential (e.g., `SECRET_KEY`, DB passwords) and keep them out of source control. Django’s checklist explicitly recommends loading `SECRET_KEY` from env or a file rather than hardcoding. ([Django Project][1])\n* SHOULD separate dev vs prod settings modules, with safe defaults for production (fail closed if critical settings are missing). ([Django Project][1])\n\n### 3.2 Minimum baseline targets (production)\n\n* MUST NOT use `manage.py runserver` as the production entrypoint; use a production-ready WSGI or ASGI server. ([Django Project][1])\n* MUST set `DEBUG = False` in production. ([Django Project][1])\n* MUST set a strong, secret `SECRET_KEY` and keep it secret; MAY use `SECRET_KEY_FALLBACKS` for safe rotation. ([Django Project][1])\n* MUST set `ALLOWED_HOSTS` to expected hosts (no wildcard unless you do your own host validation). ([Django Project][1])\n* MUST enforce HTTPS for authenticated areas (ideally site-wide for any login-capable app) and set `CSRF_COOKIE_SECURE=True` and `SESSION_COOKIE_SECURE=True` when HTTPS is used. ([Django Project][1])\n* SHOULD enable key `SecurityMiddleware` headers/settings: HSTS, Referrer-Policy, COOP, nosniff, SSL redirect (with correct proxy configuration). ([Django Project][3])\n* MUST treat user uploads as untrusted; ensure your web server never interprets them as executable content; keep `MEDIA_ROOT` separate from `STATIC_ROOT`. ([Django Project][1])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### DJANGO-DEPLOY-001: Do not use Django’s development server in production\n\nSeverity: High (if production)\n\nRequired:\n\n* MUST NOT deploy `manage.py runserver` as the production server.\n* MUST run behind a production-grade WSGI or ASGI server. ([Django Project][1])\n\nInsecure patterns:\n\n* Production docs/scripts using `python manage.py runserver 0.0.0.0:8000`.\n* Docker `CMD`/entrypoint uses `runserver`.\n* Kubernetes/Procfile/systemd units invoking `runserver`.\n\nDetection hints:\n\n* Search for `manage.py runserver`, `runserver 0.0.0.0`, `--insecure`.\n* Check Docker `CMD/ENTRYPOINT`, Procfile, systemd unit files, Helm charts.\n\nFix:\n\n* Use a production server (WSGI/ASGI) as recommended in Django’s deployment checklist. ([Django Project][1])\n\nNote:\n\n* `runserver` is fine for local development. Only flag if it’s used as the production entrypoint.\n\n---\n\n### DJANGO-DEPLOY-002: `DEBUG` MUST be disabled in production\n\nSeverity: High\n\nRequired:\n\n* MUST set `DEBUG = False` in production.\n* MUST treat any mechanism that exposes debug pages/tracebacks to untrusted users as a critical information disclosure risk. Django’s checklist explicitly warns `DEBUG=True` leaks source excerpts, local variables, settings, and more. ([Django Project][1])\n\nInsecure patterns:\n\n* `DEBUG = True` in production settings.\n* Environment defaults to `DEBUG=True` unless explicitly overridden.\n\nDetection hints:\n\n* Search `DEBUG = True`, `DEBUG=os.environ.get(..., True)`, `DJANGO_DEBUG`, `.env` files.\n* Look for “production” settings modules that import from dev defaults.\n\nFix:\n\n* Set `DEBUG=False` in prod settings; use explicit environment config.\n* Ensure error reporting is via safe logging/monitoring, not debug pages. ([Django Project][1])\n\n---\n\n### DJANGO-CONFIG-001: `SECRET_KEY` must be strong, secret, and rotated safely\n\nSeverity: High (Critical if missing in production with signing/sessions)\n\nRequired:\n\n* MUST set a large random `SECRET_KEY` in production and keep it secret. ([Django Project][1])\n* MUST NOT commit it to source control or print/log it. ([Django Project][1])\n* SHOULD load it from env or a file/secret store (not hard-coded). ([Django Project][1])\n* MAY rotate keys using `SECRET_KEY_FALLBACKS` to avoid instantly invalidating all signed data; MUST remove old keys from fallbacks in a timely manner. ([Django Project][1])\n\nInsecure patterns:\n\n* Hard-coded `SECRET_KEY = \"...\"` in repo for production.\n* `SECRET_KEY` reused across environments.\n* `SECRET_KEY_FALLBACKS` contains long-expired keys indefinitely.\n\nDetection hints:\n\n* Search for `SECRET_KEY =`, `SECRET_KEY_FALLBACKS`, `.env` committed files, `print(settings.SECRET_KEY)`.\n\nFix:\n\n* Load from secret manager / environment variable.\n* If rotating:\n\n  * Set new `SECRET_KEY`\n  * Keep old key(s) temporarily in `SECRET_KEY_FALLBACKS`\n  * Remove old key(s) after the rotation window. ([Django Project][1])\n\n---\n\n### DJANGO-HOST-001: Host header must be validated (`ALLOWED_HOSTS` must be strict)\n\nSeverity: Medium\n\nRequired:\n\n* MUST set `ALLOWED_HOSTS` in production to your expected domains/hosts. ([Django Project][1])\n* MUST NOT set `ALLOWED_HOSTS = ['*']` in production unless you also implement your own robust `Host` validation (Django warns that wildcards require your own validation to avoid CSRF-class attacks). ([Django Project][1])\n* SHOULD configure the fronting web server to reject unknown hosts early (defense-in-depth). ([Django Project][1])\n\nInsecure patterns:\n\n* `ALLOWED_HOSTS = ['*']` (or env expands to `*`) in production.\n* `ALLOWED_HOSTS = []` with `DEBUG=False` (site won’t run, or misconfigured deployments attempt workarounds).\n\nDetection hints:\n\n* Search `ALLOWED_HOSTS`.\n* Check platform environment settings that override `ALLOWED_HOSTS`.\n\nFix:\n\n* Set `ALLOWED_HOSTS = ['example.com', 'www.example.com', ...]` for prod.\n* Keep dev hosts separate.\n\nNotes:\n\n* Django uses the Host header for URL construction; fake Host values can lead to CSRF, cache poisoning, and poisoned email links (Django security docs call this out). ([Django Project][2])\n\n---\n\n### DJANGO-HTTPS-001: If TLS is used cookie transport must be secured\n\nSeverity: High (Critical for auth-enabled apps)\n\nNOTE: Only enforce this if TLS is enabled, as it will break non-TLS applications\n\nIf using TLS:\n* MUST set:\n\n  * `CSRF_COOKIE_SECURE = True` ([Django Project][1])\n  * `SESSION_COOKIE_SECURE = True` ([Django Project][1])\n* SHOULD consider enabling:\n\n  * `SECURE_SSL_REDIRECT = True` (with correct proxy config) ([Django Project][3])\n  * HSTS via `SECURE_HSTS_SECONDS` (+ includeSubDomains/preload as appropriate). ([Django Project][3])\n\nInsecure patterns:\n\n* Login pages over HTTP, or mixed HTTP/HTTPS with the same session cookie.\n* `CSRF_COOKIE_SECURE=False` or `SESSION_COOKIE_SECURE=False` in production HTTPS.\n* HSTS enabled incorrectly (can break site for the duration).\n\nDetection hints:\n\n* Inspect `settings.py` for `CSRF_COOKIE_SECURE`, `SESSION_COOKIE_SECURE`, `SECURE_SSL_REDIRECT`, `SECURE_HSTS_SECONDS`.\n* Inspect proxy/ingress config for HTTP->HTTPS redirect behavior.\n\nFix:\n\n* Enable HTTPS redirect and secure cookies.\n* Add HSTS carefully (start with low value, validate, then increase). Django warns misconfig can break your site for the HSTS duration. ([Django Project][3])\n\n---\n\n### DJANGO-PROXY-001: Reverse proxy trust must be configured correctly (`SECURE_PROXY_SSL_HEADER`)\n\nSeverity: Medium (when behind a TLS proxy)\n\nRequired:\n\n* If behind a reverse proxy that terminates TLS, MUST configure Django so `request.is_secure()` reflects the *external* scheme, otherwise CSRF and other logic can break. Django documents using `SECURE_PROXY_SSL_HEADER` for this. ([Django Project][3])\n* MUST only set `SECURE_PROXY_SSL_HEADER` if you control the proxy (or have guarantees) and it strips inbound spoofed headers. Django explicitly warns misconfig can compromise security and lists required conditions. ([Django Project][3])\n\nInsecure patterns:\n\n* `SECURE_PROXY_SSL_HEADER = (\"HTTP_X_FORWARDED_PROTO\", \"https\")` in an environment where the proxy does not strip user-supplied `X-Forwarded-Proto`.\n* Infinite redirect loops after setting `SECURE_SSL_REDIRECT=True` (often indicates proxy HTTPS detection is wrong). ([Django Project][3])\n\nDetection hints:\n\n* Search `SECURE_PROXY_SSL_HEADER`, `SECURE_SSL_REDIRECT`.\n* Inspect ingress/proxy behavior for stripping forwarded headers.\n\nFix:\n\n* Set `SECURE_PROXY_SSL_HEADER` only if the proxy strips and sets the header correctly (per Django’s documented prerequisites). ([Django Project][3])\n\n---\n\n### DJANGO-SESS-001: Session cookies must use secure attributes in production\n\nSeverity: Medium (Only if TLS enabled)\n\nRequired (production, HTTPS):\n\n* MUST set `SESSION_COOKIE_SECURE=True` (only transmit over HTTPS). ([Django Project][3])\n* MUST keep `SESSION_COOKIE_HTTPONLY=True` (Django default is `True`). ([Django Project][3])\n* SHOULD keep `SESSION_COOKIE_SAMESITE='Lax'` (Django default is `Lax`) unless a justified cross-site flow requires `None`. ([Django Project][3])\n* SHOULD avoid setting `SESSION_COOKIE_DOMAIN` unless you truly need cross-subdomain cookies (subdomain-wide cookies expand attack surface).\n\nInsecure patterns:\n\n* `SESSION_COOKIE_SECURE=False` in production HTTPS.\n\nIMPORTANT NOTE: Only set `Secure` in production environment when TLS is configured. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n\n* `SESSION_COOKIE_HTTPONLY=False`.\n* `SESSION_COOKIE_SAMESITE=None` combined with cookie-authenticated state-changing endpoints (higher CSRF risk).\n\nDetection hints:\n\n* Search for `SESSION_COOKIE_` settings, `response.set_cookie(..., httponly=..., secure=..., samesite=...)`.\n\nFix:\n\n* Set the above explicitly in production settings.\n* Validate compatibility with your auth flows. ([Django Project][3])\n\n---\n\n### DJANGO-SESS-002: CSRF cookie settings must be deliberate (HttpOnly has tradeoffs)\n\nSeverity: Medium\n\nRequired:\n\n* SHOULD set `CSRF_COOKIE_SECURE=True` when using HTTPS/TLS. ([Django Project][3])\n* SHOULD keep `CSRF_COOKIE_SAMESITE='Lax'` unless you have a cross-site requirement. Django default is `Lax`. ([Django Project][3])\n* MAY set `CSRF_COOKIE_HTTPONLY=True` (default is `False`) if your frontend does not need to read the CSRF cookie. If you enable it, your JS must read the CSRF token from the DOM instead (Django documents this). ([Django Project][3])\n\nInsecure patterns:\n\n* `CSRF_COOKIE_SECURE=False` in production HTTPS/TLS.\n* Setting `CSRF_COOKIE_HTTPONLY=True` but still relying on “read csrftoken cookie in JS” patterns (breaks CSRF for AJAX).\n* `CSRF_COOKIE_SAMESITE=None` without a clear reason.\n\nDetection hints:\n\n* Search for `CSRF_COOKIE_` settings.\n* Search JS for `document.cookie` usage to fetch `csrftoken`.\n\nFix:\n\n* Align cookie settings with your CSRF token acquisition method (cookie vs DOM) as Django describes. ([Django Project][4])\n\n---\n\n### DJANGO-CSRF-001: Cookie-authenticated state-changing requests MUST be CSRF-protected\n\nSeverity: High\n\nRequired:\n\n* MUST keep `django.middleware.csrf.CsrfViewMiddleware` enabled (it is activated by default). ([Django Project][4])\n* MUST include `{% csrf_token %}` in internal POST forms; MUST NOT include it in forms that POST to external URLs (Django warns this leaks the token). ([Django Project][4])\n* MUST protect all state-changing endpoints (POST/PUT/PATCH/DELETE) that rely on cookies for authentication.\n* For AJAX/SPA calls, MUST send the CSRF token via the `X-CSRFToken` header (or configured header name) as documented. ([Django Project][4])\n* MUST be very careful with `@csrf_exempt` and use it only when absolutely necessary; if used, MUST replace CSRF with an appropriate alternative control (e.g., request signing for webhooks). Django explicitly warns about `csrf_exempt`. ([Django Project][2])\n\nInsecure patterns:\n\n* Missing `CsrfViewMiddleware` in `MIDDLEWARE`.\n* `@csrf_exempt` on general-purpose authenticated views.\n* POST/PUT/PATCH/DELETE endpoints with session auth and no CSRF tokens.\n* Using GET for state-changing actions (amplifies CSRF risk).\n\nDetection hints:\n\n* Inspect `settings.py` `MIDDLEWARE` for `CsrfViewMiddleware` and its order (Django notes it should come before middleware that assumes CSRF is handled). ([Django Project][4])\n* Search for `csrf_exempt`, `csrf_protect`, `ensure_csrf_cookie`.\n* Enumerate URL patterns for non-GET methods; confirm CSRF coverage.\n\nFix:\n\n* Re-enable `CsrfViewMiddleware`, add CSRF tokens to forms, and add AJAX header handling.\n* For caching decorators: if you cache a view that needs CSRF tokens, apply `@csrf_protect` as Django documents to avoid caching a response without CSRF cookie/Vary headers. ([Django Project][4])\n\nNotes:\n\n* When deployed with HTTPS, Django’s CSRF middleware also checks the Referer header for same-origin (Django security docs mention this). ([Django Project][2])\n\n---\n\n### DJANGO-XSS-001: Prevent reflected/stored XSS in templates and HTML generation\n\nSeverity: High\n\nRequired:\n\n* MUST rely on Django template auto-escaping (safe-by-default) for HTML templates. Django security docs highlight that Django templates escape dangerous characters but have limitations. ([Django Project][2])\n* MUST NOT disable auto-escaping broadly (`{% autoescape off %}`) unless the content is trusted or safely sanitized. ([Django Project][5])\n* MUST NOT mark untrusted content as safe:\n\n  * Avoid `mark_safe(...)` on user data.\n  * Avoid `|safe` on user-controlled content.\n* MUST be careful about HTML context pitfalls (e.g., unquoted attributes); Django explicitly shows an example where escaping does not protect an unquoted attribute context. ([Django Project][2])\n* SHOULD prefer safe HTML construction helpers (e.g., `format_html`) rather than manual concatenation that risks missing escapes. ([Django Project][6])\n\nInsecure patterns:\n\n* `{% autoescape off %}{{ user_input }}{% endautoescape %}`\n* `{{ user_input|safe }}`\n* `mark_safe(request.GET[\"q\"])`\n* Unquoted attribute injections: `<style class={{ var }}>...` (Django’s own example). ([Django Project][2])\n\nDetection hints:\n\n* Search templates for `|safe`, `autoescape off`, `safeseq`.\n* Search Python for `mark_safe`, `SafeString`, or direct HTML concatenation with request/DB values.\n* Review any code returning `HttpResponse(user_value)` where `user_value` contains HTML.\n\nFix:\n\n* Remove unsafe marking; sanitize only when strictly necessary (use an allowlist-based HTML sanitizer).\n* Quote attributes and avoid placing untrusted values into dangerous contexts.\n* Add CSP as defense-in-depth (see DJANGO-CSP-001). ([Django Project][2])\n\n---\n\n### DJANGO-TEMPLATE-001: Never render untrusted template source strings\n\nSeverity: High to Critical (depends on context and exposure)\n\nRequired:\n\n* MUST NOT render templates where the template source string is influenced by untrusted input (request, user content, DB rows editable by untrusted users).\n* MUST treat “template from string” patterns as dangerous, even if Django templates are more constrained than some other engines: they can still leak data from context, bypass escaping, and create XSS or content injection.\n\nInsecure patterns:\n\n* `Template(request.GET[\"tmpl\"]).render(Context(...))`\n* Saving user templates in the DB and rendering them with normal privileges/context.\n\nDetection hints:\n\n* Search for `django.template.Template(`, `Engine.from_string`, `.render(Context(` with non-constant strings.\n* Trace where the template string comes from (admin panels, DB, uploads, requests).\n\nFix:\n\n* Replace with non-executing formatting (e.g., `string.Template`, explicit placeholders) or a strict allowlisted rendering model.\n* If you *must* support user-defined templates, isolate heavily (separate service/tenant context, strict allowlists, and assume bypasses are possible).\n\n---\n\n### DJANGO-SQL-001: Prevent SQL injection (use ORM or parameterized raw SQL)\n\nSeverity: High\n\nRequired:\n\n* MUST use Django ORM/querysets for normal DB access; Django notes querysets are parameterized and protected from SQL injection under typical use. ([Django Project][2])\n* MUST be very careful with raw SQL; if using `raw()`, `cursor.execute()`, `extra()`, or `RawSQL`, MUST pass parameters separately (e.g., `params=`) and MUST NOT string-interpolate untrusted input into SQL. Django’s raw SQL docs warn to escape user-controlled parameters using `params`. ([Django Project][7])\n* MUST NOT quote placeholders in SQL templates (Django docs explicitly warn that quoting `%s` placeholders makes it unsafe). ([Django Project][8])\n* SHOULD avoid `extra()` and `RawSQL` unless necessary; Django security docs call for caution. ([Django Project][2])\n\nInsecure patterns:\n\n* `cursor.execute(f\"SELECT ... WHERE id={request.GET['id']}\")`\n* `Model.objects.raw(\"... %s\" % user_input)` (string formatting)\n* `extra(where=[f\"headline='{q}'\"])`\n* Quoted placeholders: `WHERE othercol = '%s'` (explicitly documented as unsafe). ([Django Project][8])\n\nDetection hints:\n\n* Grep for `.raw(`, `.extra(`, `RawSQL(`, `connection.cursor()`, `.execute(`.\n* Grep for SQL keywords (`SELECT`, `UPDATE`, `DELETE`, `INSERT`) in Python strings.\n* Track untrusted inputs into these call sites.\n\nFix:\n\n* Prefer ORM queries.\n* If raw SQL is unavoidable, use parameters (`params`, DB-API param binding) and do not quote placeholders. ([Django Project][7])\n\n---\n\n### DJANGO-CMD-001: Prevent OS command injection\n\nSeverity: Critical to High (depends on exposure)\n\nRequired:\n\n* MUST avoid executing system commands with attacker-influenced input.\n* If subprocess is necessary:\n\n  * MUST pass args as a list (not a shell string).\n  * MUST NOT use `shell=True` with attacker-influenced content.\n  * SHOULD use strict allowlists for variable components.\n* SHOULD prefer pure-Python libraries instead of shelling out.\n\nInsecure patterns:\n\n* `os.system(request.GET[\"cmd\"])`\n* `subprocess.run(f\"convert {path}\", shell=True)` where `path` is user-controlled.\n\nDetection hints:\n\n* Search `os.system`, `subprocess`, `Popen`, `shell=True`.\n* Trace request/DB inputs into those calls.\n\nFix:\n\n* Replace with library APIs; if unavoidable, hard-code executable and allowlist validated parameters.\n\n---\n\n### DJANGO-UPLOAD-001: File uploads must be validated, stored safely, and served safely\n\nSeverity: High\n\nRequired:\n\n* MUST treat all user uploads as untrusted. Django explicitly warns “Media files are uploaded by your users. They’re untrusted!” ([Django Project][1])\n* MUST ensure the web server never interprets user uploads as executable code (e.g., don’t allow uploaded `.php` or HTML to execute/inline as active content). ([Django Project][1])\n* MUST enforce size limits (at least at the web server; Django security docs recommend limiting upload size at the server to prevent DoS). ([Django Project][2])\n* SHOULD validate file types using allowlists and content checks (not only extensions).\n* SHOULD store uploads outside the application code directory and outside any static root.\n* SHOULD consider serving uploads from a separate top-level/second-level domain to reduce same-origin impact; Django security docs recommend a distinct domain and note that a subdomain may be insufficient for some protections. ([Django Project][2])\n* MUST be aware of polyglot upload risks: Django documents a case where HTML can be uploaded “as an image” by using a valid PNG header (and may be served as HTML depending on the web server). ([Django Project][2])\n\nInsecure patterns:\n\n* Serving uploads inline with `text/html` or without forcing download for potentially active formats.\n* Upload allowlist based only on extension.\n* Upload storage inside static roots or code roots.\n\nDetection hints:\n\n* Search for `request.FILES`, `FileField`, `ImageField`, upload forms/views.\n* Inspect upload serving paths and Nginx/Apache config (media handlers).\n* Check `MEDIA_URL`, `MEDIA_ROOT`, and static config.\n\nFix:\n\n* Configure the web server to serve uploads as inert bytes (no execution), and consider forcing `Content-Disposition: attachment` for risky types.\n* Use a separate domain for user content when warranted. ([Django Project][2])\n\n---\n\n### DJANGO-PATH-001: Prevent path traversal and unsafe file serving (static/media separation)\n\nSeverity: High\n\nRequired:\n\n* MUST NOT treat user input as a filesystem path for reads/writes/serving.\n* MUST keep `MEDIA_ROOT` and `STATIC_ROOT` distinct; Django settings docs explicitly warn they must have different values to avoid security implications. ([Django Project][3])\n* SHOULD prefer using Django storage APIs keyed by server-side identifiers rather than accepting arbitrary relative paths from users.\n\nInsecure patterns:\n\n* `open(os.path.join(MEDIA_ROOT, request.GET[\"path\"]))`\n* Download endpoints that take `?file=../../...` style parameters.\n* Misconfigured `MEDIA_ROOT == STATIC_ROOT`.\n\nDetection hints:\n\n* Grep for `open(`, `Path(`, `os.path.join(` used with request values.\n* Check `MEDIA_ROOT`, `STATIC_ROOT` in settings. ([Django Project][3])\n\nFix:\n\n* Use server-side IDs mapped to known files.\n* Keep static and media separated and ensure the web server treats media as untrusted. ([Django Project][3])\n\n---\n\n### DJANGO-REDIRECT-001: Prevent open redirects (`next`, `return_to`, `redirect`)\n\nSeverity: Medium (High when combined with auth flows)\n\nRequired:\n\n* MUST validate redirect targets derived from untrusted input (e.g., `next`, `return_to`).\n* SHOULD restrict to same-site relative paths or allowlisted hosts/schemes.\n* SHOULD use Django’s safe URL helpers (e.g., `django.utils.http.url_has_allowed_host_and_scheme`) rather than custom parsing.\n\nInsecure patterns:\n\n* `return redirect(request.GET.get(\"next\"))` with no validation.\n* Redirect allowlist implemented with naive string checks.\n\nDetection hints:\n\n* Search for `redirect(` and track origin of the target.\n* Search for parameters named `next`, `return_to`, `redirect`, `url`.\n\nFix:\n\n* Validate with allowlists and default to a safe internal path if validation fails.\n* Ensure host validation via `ALLOWED_HOSTS` remains strict (see DJANGO-HOST-001). ([Django Project][3])\n\n---\n\n### DJANGO-HEADERS-001: Enable essential security headers (SecurityMiddleware + clickjacking protection)\n\nSeverity: Medium to High\n\nRequired:\n\n* SHOULD use `django.middleware.security.SecurityMiddleware` and configure it appropriately (production) for:\n\n  * `X-Content-Type-Options: nosniff` (Django setting `SECURE_CONTENT_TYPE_NOSNIFF`, default `True`). ([Django Project][3])\n  * `Referrer-Policy` (Django setting `SECURE_REFERRER_POLICY`, default `'same-origin'`). ([Django Project][3])\n  * COOP (Django setting `SECURE_CROSS_ORIGIN_OPENER_POLICY`, default `'same-origin'`). ([Django Project][3])\n  * HTTPS redirects and HSTS as appropriate (see DJANGO-HTTPS-001). ([Django Project][3])\n* SHOULD enable clickjacking protection via X-Frame-Options middleware; Django security docs strongly recommend it for sites that don’t need third-party framing. ([Django Project][2])\n\nInsecure patterns:\n\n* Missing SecurityMiddleware.\n* Missing clickjacking protection (or disabling it globally) without a clear framing requirement.\n* Over-broad framing allowances for sensitive endpoints.\n\nDetection hints:\n\n* Inspect `MIDDLEWARE` for SecurityMiddleware and XFrameOptionsMiddleware.\n* Search for per-view disabling of framing/CSRF protections.\n\nFix:\n\n* Add/enable middleware and configure the settings intentionally. ([Django Project][3])\n\nNOTE:\n\n* Some headers may be set at the edge (CDN/reverse proxy). If not visible in app code, flag as “verify at edge”.\n\n---\n\n### DJANGO-CSP-001: Deploy a Content Security Policy (CSP) as defense-in-depth\n\nSeverity: Medium (High for apps rendering untrusted content)\n\nNOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n\nRequired:\n\n* SHOULD deploy a CSP to mitigate XSS and content injection classes; Django’s security docs recommend CSP and note it is new in Django 6.0. ([Django Project][2])\n* MUST understand CSP limitations:\n\n  * Avoid excluding routes from CSP coverage; Django warns that an unprotected page can undermine protected pages due to same-origin policy. ([Django Project][2])\n* MAY start with `SECURE_CSP_REPORT_ONLY` to iterate safely (Django provides report-only support). ([Django Project][3])\n\nInsecure patterns:\n\n* No CSP on apps that render user-controlled content.\n* CSP excludes “just a couple pages” (weakens overall protection), especially pages with any injection surface. ([Django Project][2])\n* CSP uses overly permissive directives (e.g., widespread `unsafe-inline`) without justification.\n\nDetection hints:\n\n* Search `SECURE_CSP`, `SECURE_CSP_REPORT_ONLY`, and CSP middleware configuration.\n* Inspect reverse proxy/CDN config for CSP headers.\n\nFix:\n\n* Implement a realistic CSP, ideally report-only first, then enforce. ([Django Project][3])\n\n---\n\n### DJANGO-AUTH-001: Password storage must use Django’s secure hashers; password policy must be configured\n\nSeverity: High\n\nRequired:\n\n* MUST use Django’s built-in password hashing (never store plaintext or reversible encrypted passwords).\n* SHOULD prefer modern hashers and keep defaults updated; Django documents `PASSWORD_HASHERS` and includes modern options (Argon2, bcrypt, scrypt, PBKDF2 variants). ([Django Project][3])\n* SHOULD configure `AUTH_PASSWORD_VALIDATORS` (default is empty) for production password policy. ([Django Project][3])\n\nInsecure patterns:\n\n* Custom password storage or hashing.\n* Plaintext passwords stored in DB fields.\n* No password validation on consumer-facing apps.\n\nDetection hints:\n\n* Search for `.set_password(` usage vs manual hashing.\n* Inspect settings for `PASSWORD_HASHERS` and `AUTH_PASSWORD_VALIDATORS`. ([Django Project][3])\n\nFix:\n\n* Use Django auth user model APIs.\n* Enable password validators appropriate to the product’s risk profile. ([Django Project][3])\n\n---\n\n### DJANGO-AUTHZ-001: Authorization must be explicit and consistent\n\nSeverity: High\n\nRequired:\n\n* MUST enforce authorization checks on every privileged action (view, modify, admin-like operations).\n* MUST NOT rely on UI-only restrictions (e.g., hiding buttons) without server-side permission checks.\n* SHOULD use Django’s permissions/groups and per-object authorization patterns where applicable.\n\nInsecure patterns:\n\n* Views that assume “user is logged in” implies “user may do action”.\n* Missing authorization checks on update/delete endpoints.\n\nDetection hints:\n\n* Enumerate views that modify state; ensure they validate ownership/permission.\n* Look for use of only `is_authenticated` or only `is_staff` without checking object-level access.\n\nFix:\n\n* Add explicit permission checks and tests for unauthorized access.\n\n---\n\n### DJANGO-ADMIN-001: Django admin must be treated as a high-value target\n\nSeverity: High\n\nRequired:\n\n* MUST ensure admin is protected by strong authentication and HTTPS-only transport (see DJANGO-HTTPS-001). ([Django Project][1])\n* SHOULD restrict admin exposure (network allowlists, VPN, SSO, or additional authentication controls) when possible.\n* SHOULD audit installed admin extensions and third-party apps for XSS/CSRF exposure.\n\nInsecure patterns:\n\n* Admin exposed to the internet with weak authentication.\n* Admin served over HTTP.\n\nDetection hints:\n\n* Search `urlpatterns` for `admin.site.urls`.\n* Check deployment config for IP allowlisting or auth gateways.\n\nFix:\n\n* Add network controls and enforce HTTPS.\n\n---\n\n### DJANGO-LOG-001: Logging and error reporting must not leak secrets\n\nSeverity: Medium to High\n\nRequired:\n\n* MUST NOT log secrets (including `SECRET_KEY`, session cookies, auth headers, password reset tokens).\n* MUST configure production logging deliberately; Django’s deployment checklist explicitly calls out reviewing logging before production. ([Django Project][1])\n* MUST ensure `DEBUG=False` in production so exceptions aren’t rendered with sensitive context. ([Django Project][1])\n\nInsecure patterns:\n\n* Logging full request headers or cookies in production.\n* Printing settings dictionaries.\n* Debug error pages.\n\nDetection hints:\n\n* Inspect `LOGGING` config; search for middleware that logs request headers/cookies.\n* Grep for `print(settings` / `logging.info(request.META)` patterns.\n\nFix:\n\n* Redact sensitive values; log IDs not secrets.\n* Use structured logging and a safe error monitoring tool. ([Django Project][1])\n\n---\n\n### DJANGO-SUPPLY-001: Dependency and patch hygiene (Django + security-critical deps)\n\nSeverity: Medium (High if known vulnerable versions)\n\nRequired:\n\n* SHOULD pin and regularly update Django and security-critical dependencies.\n* MUST respond to Django security releases promptly.\n\nDetection hints:\n\n* Check `requirements.txt`, lockfiles, build images.\n* Identify Django version; compare against latest supported release (Django’s download page publishes current stable and supported branches). ([Django Project][9])\n\nFix:\n\n* Upgrade to patched versions; add regression tests for previously vulnerable classes.\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* Deployment/dev server:\n\n  * `manage.py runserver`, `runserver 0.0.0.0`, `--insecure` ([Django Project][1])\n* Debug / settings:\n\n  * `DEBUG = True` ([Django Project][1])\n  * `SECRET_KEY =`, `SECRET_KEY_FALLBACKS` ([Django Project][1])\n* Host validation:\n\n  * `ALLOWED_HOSTS = ['*']` ([Django Project][3])\n* HTTPS and proxy:\n\n  * `SECURE_SSL_REDIRECT`, `SECURE_HSTS_SECONDS`, `SECURE_PROXY_SSL_HEADER` ([Django Project][3])\n* Cookies / sessions:\n\n  * `SESSION_COOKIE_SECURE`, `SESSION_COOKIE_HTTPONLY`, `SESSION_COOKIE_SAMESITE` ([Django Project][3])\n  * `CSRF_COOKIE_SECURE`, `CSRF_COOKIE_HTTPONLY`, `CSRF_COOKIE_SAMESITE` ([Django Project][3])\n* CSRF bypasses:\n\n  * `csrf_exempt`, missing `CsrfViewMiddleware`, POST forms without `{% csrf_token %}` ([Django Project][4])\n* XSS:\n\n  * `|safe`, `autoescape off`, `mark_safe(`, HTML string concatenation ([Django Project][5])\n* SQL injection:\n\n  * `.raw(`, `.extra(`, `RawSQL(`, `cursor.execute(` with formatted SQL strings ([Django Project][7])\n* User uploads / media:\n\n  * `request.FILES`, `MEDIA_ROOT`, `MEDIA_URL`, serving media inline; `MEDIA_ROOT == STATIC_ROOT` ([Django Project][1])\n* Redirects:\n\n  * `redirect(request.GET.get(\"next\"))` patterns; missing allowlist validation\n* Security headers and CSP:\n\n  * Missing `SecurityMiddleware`, missing X-Frame-Options protection, missing `SECURE_CSP` adoption (where appropriate) ([Django Project][2])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (template/SQL/subprocess/files/redirect/http)\n* protective controls present (middleware, validation, allowlists, authz checks)\n* whether security headers/controls are set in-app vs at the edge\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary Django documentation:\n\n```text\n- Django Downloads (current stable & supported branches): https://www.djangoproject.com/download/\n- Django 6.0 Release Notes: https://docs.djangoproject.com/en/6.0/releases/6.0/\n- Django: Deployment checklist (incl. check --deploy, runserver warning, HTTPS/cookies guidance): https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/\n- Django: Settings reference (SecurityMiddleware settings, cookies, SECRET_KEY_FALLBACKS, CSP settings): https://docs.djangoproject.com/en/6.0/ref/settings/\n- Django: Security in Django (XSS/CSRF/SQLi/clickjacking/HTTPS/host header validation/uploads/CSP): https://docs.djangoproject.com/en/6.0/topics/security/\n- Django: CSRF how-to (middleware, csrf_token usage, AJAX header patterns, csrf_exempt cautions): https://docs.djangoproject.com/en/6.0/howto/csrf/\n- Django: Performing raw SQL queries (parameterization guidance): https://docs.djangoproject.com/en/6.0/topics/db/sql/\n- Django: QuerySet API reference (extra() cautions; “do not quote placeholders” guidance): https://docs.djangoproject.com/en/6.0/ref/models/querysets/\n- Django: Template built-ins (autoescape tag): https://docs.djangoproject.com/en/6.0/ref/templates/builtins/\n- Django: Template language reference (turning off autoescape & risks): https://docs.djangoproject.com/en/6.0/ref/templates/language/\n- Django: Utilities reference (e.g., format_html): https://docs.djangoproject.com/en/6.0/ref/utils/\n```\n\nOWASP:\n\n```text\n- OWASP Cheat Sheet Series: Django Security Cheat Sheet: https://cheatsheetseries.owasp.org/cheatsheets/Django_Security_Cheat_Sheet.html\n```\n\n[1]: https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/ \"https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/\"\n[2]: https://docs.djangoproject.com/en/6.0/topics/security/ \"Security in Django | Django documentation | Django\"\n[3]: https://docs.djangoproject.com/en/6.0/ref/settings/ \"Settings | Django documentation | Django\"\n[4]: https://docs.djangoproject.com/en/6.0/howto/csrf/ \"How to use Django’s CSRF protection | Django documentation | Django\"\n[5]: https://docs.djangoproject.com/en/6.0/ref/templates/builtins/ \"https://docs.djangoproject.com/en/6.0/ref/templates/builtins/\"\n[6]: https://docs.djangoproject.com/en/6.0/ref/utils/ \"https://docs.djangoproject.com/en/6.0/ref/utils/\"\n[7]: https://docs.djangoproject.com/en/6.0/topics/db/sql/ \"https://docs.djangoproject.com/en/6.0/topics/db/sql/\"\n[8]: https://docs.djangoproject.com/en/6.0/ref/models/querysets/ \"https://docs.djangoproject.com/en/6.0/ref/models/querysets/\"\n[9]: https://www.djangoproject.com/download/ \"Download Django | Django\"\n","core/skills/builtin/security-best-practices/references/python-fastapi-web-server-security.md":"# FastAPI (Python) Web Security Spec (FastAPI 0.128.x, Python 3.x) ([PyPI][1])\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new FastAPI code.\n2. **Security review / vulnerability hunting** in existing FastAPI code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\nFastAPI is commonly deployed with an ASGI server (e.g., Uvicorn) and is built on Starlette + Pydantic, so this spec covers those layers where they affect security. ([PyPI][1])\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session cookies, signing keys, database URLs with credentials).\n* MUST NOT “fix” security by disabling protections (e.g., weakening auth, making CORS permissive, skipping signature checks, disabling validation, turning off TLS verification, adding `allow_origins=[\"*\"]` with credentials).\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and configuration values that justify the claim.\n* MUST treat uncertainty honestly: if a protection might exist in infrastructure (reverse proxy, WAF, CDN, service mesh), report it as “not visible in app code; verify at runtime/config”.\n* MUST treat browser controls correctly:\n\n  * CORS is **not** an auth mechanism; it only affects browsers.\n  * CSRF defenses apply when the browser automatically attaches credentials (cookies); they are usually not relevant for purely header-token APIs. ([OWASP Cheat Sheet Series][2])\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new FastAPI code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default APIs and proven libraries over custom security code.\n* MUST avoid introducing new risky sinks (shell execution, unsafe deserialization, dynamic eval, untrusted template rendering, unsafe file serving, unsafe redirects, arbitrary outbound fetching).\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a FastAPI repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. App entrypoints / deployment scripts / Dockerfiles / Procfiles / Helm/terraform.\n2. ASGI server configuration (Uvicorn/Gunicorn), proxy settings, debug/reload settings.\n3. FastAPI app configuration (docs exposure, middleware, trusted hosts, CORS).\n4. Authn/Authz design (dependencies, JWT/session handling, password storage).\n5. Cookie/session usage + CSRF (if cookies are used).\n6. Input validation and output shaping (Pydantic models, mass assignment, excessive data exposure).\n7. Template rendering and XSS/SSTI (if HTML is served).\n8. File handling (uploads + downloads), StaticFiles, Range support.\n9. Injection classes (SQL, command execution, unsafe deserialization).\n10. Outbound requests (SSRF), redirect handling, WebSockets security.\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nExamples include:\n\n* Query parameters / path parameters\n* JSON bodies (including nested fields)\n* Headers (including `Host`, `Origin`, `X-Forwarded-*`)\n* Cookies (including session cookies)\n* File uploads (multipart parts)\n* WebSocket messages, query params, and headers during handshake ([Starlette][3])\n* Any data from external systems (webhooks, third-party APIs, message queues)\n* Any persisted user content (DB rows) that originated from users\n\n### 2.2 State-changing request\n\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook send), or initiate privileged actions.\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + function/route name + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common FastAPI/ASGI misconfigurations.\n\nBaseline goals:\n\n* No debug tracebacks or auto-reload in production. ([PyPI][4])\n* Run under a production ASGI server configuration (workers, timeouts, resource controls). ([PyPI][4])\n* Host header validation enabled (TrustedHostMiddleware or equivalent). ([PyPI][5])\n* CORS disabled unless explicitly needed; if enabled, it is strict and least-privilege. ([OWASP Cheat Sheet Series][6])\n* Auth is enforced consistently via dependencies (no “oops, forgot auth on this route”). ([FastAPI][7])\n* If cookies/sessions are used, cookie flags are secure and CSRF is addressed. ([OWASP Cheat Sheet Series][8])\n* Request size limits and multipart limits exist at the edge and are validated in app as needed (to mitigate memory/CPU DoS). ([advisories.gitlab.com][9])\n* Dependencies are patched promptly, especially Starlette/python-multipart (multiple DoS and traversal advisories exist historically). ([advisories.gitlab.com][10])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### FASTAPI-DEPLOY-001: Do not use auto-reload / dev-only server modes in production\n\nSeverity: High (if production)\n\nRequired:\n\n* MUST NOT run production using auto-reload/watch mode (e.g., Uvicorn reload).\n* MUST run with a production process model (e.g., multiple workers where appropriate) and stable server settings. ([PyPI][4])\n\nInsecure patterns:\n\n* `uvicorn ... --reload` (or equivalent “reload=True” configs) in production entrypoints.\n* Docker/Procfile/systemd commands that run with `--reload` in production.\n\nDetection hints:\n\n* Search for `--reload`, `reload=True`, `watchfiles`, `fastapi dev`, “development” run scripts.\n* Check Docker CMD/ENTRYPOINT, Procfile, systemd units, shell scripts.\n\nFix:\n\n* Remove reload in production; run Uvicorn/Gunicorn with stable settings and explicit worker configuration. ([PyPI][4])\n\nNote:\n\n* Reload is fine for local development. Only flag when it is clearly used as a production entrypoint.\n\n---\n\n### FASTAPI-DEPLOY-002: Debug mode MUST be disabled in production\n\nSeverity: Critical\n\nRequired:\n\n* MUST NOT enable debug tracebacks in production (FastAPI/Starlette debug mode can expose sensitive internals and make some exploit chains easier). ([PyPI][5])\n* MUST treat any configuration that returns detailed stack traces to clients as sensitive.\n\nInsecure patterns:\n\n* `app = FastAPI(debug=True)` (or Starlette `debug=True`), or equivalent environment toggles enabling debug in production. ([PyPI][5])\n* Server/log config that exposes tracebacks to end users.\n\nDetection hints:\n\n* Search for `debug=True`, `DEBUG = True`, environment flags mapped to debug.\n* Review exception middleware and error handler setup.\n\nFix:\n\n* Ensure debug is only enabled in local dev/test.\n* Return generic error responses to clients; log details internally.\n\n---\n\n### FASTAPI-OPENAPI-001: OpenAPI and interactive docs MUST be disabled or protected in production\n\nSeverity: Medium (can be High in sensitive/internal apps)\n\nRequired:\n\n* SHOULD disable `/docs`, `/redoc`, and `/openapi.json` in production for public-facing services unless there is an explicit business need.\n* If enabled, MUST protect them (e.g., auth, network allowlists, or internal-only routing).\n* MUST NOT assume “security through obscurity”; treat docs exposure as an information disclosure amplifier.\n\nInsecure patterns:\n\n* Publicly reachable `/docs` and `/openapi.json` for internal/admin APIs.\n* Docs enabled on the same hostname as production without access control.\n\nDetection hints:\n\n* Look for `FastAPI(docs_url=..., redoc_url=..., openapi_url=...)` or defaults.\n* Check reverse proxy routing and allowlists.\n\nFix:\n\n* Disable docs endpoints in prod (`docs_url=None`, `redoc_url=None`, `openapi_url=None`) or restrict access at the edge.\n\n---\n\n### FASTAPI-AUTH-001: Authentication MUST be explicit and consistently enforced via dependencies\n\nSeverity: High\n\nRequired:\n\n* MUST implement authentication as a dependency (or router-level dependency) so that protected endpoints cannot “forget” auth.\n* MUST default to “deny” for privileged routers/endpoints; explicitly mark truly public routes.\n* SHOULD centralize auth enforcement at router boundaries (e.g., protected `APIRouter` for authenticated endpoints). ([FastAPI][7])\n\nInsecure patterns:\n\n* Per-route ad-hoc auth checks scattered through handlers (easy to miss).\n* A mix of protected/unprotected endpoints with no clear policy.\n\nDetection hints:\n\n* Identify routers and endpoints; check whether protected ones include `Depends(...)`/`Security(...)`.\n* Search for patterns like `if user is None: raise ...` inside handlers (instead of dependencies).\n\nFix:\n\n* Move authentication into a dependency and attach it to the router/endpoint consistently using `Depends()`/`Security()`. ([FastAPI][7])\n\n---\n\n### FASTAPI-AUTH-002: Use standard auth transports; avoid secrets in URLs\n\nSeverity: High\n\nRequired:\n\n* SHOULD use the `Authorization: Bearer <token>` header for token auth, not query parameters. ([FastAPI][11])\n* MUST NOT place secrets (tokens, reset links containing long-lived secrets, API keys) in query strings when avoidable.\n\nInsecure patterns:\n\n* `?token=...`, `?api_key=...`, `?auth=...` used for primary auth.\n* Long-lived access tokens embedded in URLs (leak via logs, referrers, caches).\n\nDetection hints:\n\n* Search for parameter names like `token`, `api_key`, `key`, `secret`, `password`.\n* Look for security schemes that use query API keys without justification.\n\nFix:\n\n* Move tokens to Authorization headers; rotate/shorten lifetimes; use POST bodies for sensitive values.\n\n---\n\n### FASTAPI-AUTH-003: Password storage MUST be strongly hashed; never store plaintext passwords\n\nSeverity: Critical\n\nRequired:\n\n* MUST store passwords using a strong, slow password hashing scheme (e.g., Argon2id, bcrypt).\n* MUST NOT store plaintext passwords, or reversible encryption as the primary protection.\n* SHOULD use established libraries for hashing and verification (do not roll your own).\n\nInsecure patterns:\n\n* Storing plaintext passwords in DB.\n* Using fast hashes (e.g., SHA256) without a proper password hashing KDF.\n* Returning password hashes in API responses.\n\nDetection hints:\n\n* Search for `password=` persisted fields, and look for `hashlib.md5/sha1/sha256` usage on passwords.\n* Inspect response models for password/hash fields.\n\nFix:\n\n* Migrate to a proper password hashing library; add a re-hash-on-login upgrade path.\n\n---\n\n### FASTAPI-AUTH-004: JWT validation MUST be strict; JWTs MUST NOT carry secrets\n\nSeverity: High\n\nRequired:\n\n* MUST validate JWT signature and enforce an algorithm allowlist.\n* MUST validate standard claims appropriate to your system (at least `exp`; typically also `iss`/`aud` if multi-service or multi-tenant).\n* MUST treat JWT contents as readable by the client; do not put secrets in JWT payloads. ([FastAPI][12])\n\nInsecure patterns:\n\n* `jwt.decode(..., options={\"verify_signature\": False})` or equivalent.\n* Accepting `alg=none` / algorithm confusion.\n* Using JWT payload to store sensitive secrets (API keys, passwords).\n\nDetection hints:\n\n* Search for `jwt.decode`, `python-jose`, `PyJWT`, `verify_signature`.\n* Check for missing exp validation or long expirations.\n\nFix:\n\n* Enforce strict validation (signature, allowed algorithms, exp, and any required issuer/audience constraints).\n* Store only identifiers/claims you are comfortable exposing to the client. ([FastAPI][12])\n\n---\n\n### FASTAPI-AUTHZ-001: Authorization MUST be enforced per-object and per-property\n\nSeverity: High\n\nRequired:\n\n* MUST perform object-level authorization whenever accessing a resource by user-controlled identifier (ID in path/query/body).\n* MUST perform property-level authorization and response shaping to prevent “excessive data exposure” (e.g., admin-only fields). ([OWASP Foundation][13])\n\nInsecure patterns:\n\n* `GET /users/{id}` returns user record without verifying caller can access that `id`.\n* Response models include internal fields (roles, permissions, billing data, password hashes).\n\nDetection hints:\n\n* Enumerate endpoints that accept IDs; trace whether an authz check is performed.\n* Compare response models for public vs internal fields.\n\nFix:\n\n* Add object-level checks (ownership, ACLs, tenant boundaries).\n* Use dedicated response models that include only allowed fields.\n\n---\n\n### FASTAPI-SESS-001: If using cookie-based sessions and TLS, cookie attributes MUST be secure in production\n\nSeverity: High (only if TLS is enabled)\n\nRequired (production, HTTPS):\n\n* MUST set session cookies to be sent only over HTTPS (secure). IMPORTANT NOTE: Only set `Secure` in production environment when TLS is configured. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n* MUST set HttpOnly for session cookies (not accessible to JS).\n* SHOULD use `SameSite=Lax` (or `Strict` if UX allows); if you require cross-site cookies, document the CSRF implications and add compensating controls. ([OWASP Cheat Sheet Series][8])\n* If using Starlette `SessionMiddleware`, MUST set `https_only=True` in production and choose an appropriate `same_site`. ([PyPI][5])\n\nInsecure patterns:\n\n* Session cookies without Secure/HttpOnly.\n* `SameSite=None` cookies used for authenticated state-changing endpoints without CSRF protections.\n\nDetection hints:\n\n* Search for `SessionMiddleware(` and inspect parameters like `https_only`, `same_site`.\n* Search for `set_cookie(` usage and cookie flags.\n\nFix:\n\n* Set secure cookie attributes; prefer short lifetimes for high-privilege sessions. ([OWASP Cheat Sheet Series][8])\n\n---\n\n### FASTAPI-SESS-002: Do not store sensitive secrets in signed session cookies\n\nSeverity: High\n\nRequired:\n\n* MUST assume cookie-based session data is readable by the client (signed ≠ encrypted); do not store secrets/PII unless encrypted server-side.\n* Store only opaque identifiers (e.g., session ID) or non-sensitive state in the cookie; store sensitive session state server-side. ([OWASP Cheat Sheet Series][8])\n\nInsecure patterns:\n\n* Storing access tokens, refresh tokens, or PII directly in cookie session payloads.\n* Treating “signed cookies” as confidential storage.\n\nDetection hints:\n\n* Search for `request.session[...] =` or `session[...] =`-equivalent patterns; identify what is stored.\n* Identify use of `SessionMiddleware` or other cookie session mechanisms.\n\nFix:\n\n* Move sensitive values to server-side storage; keep cookie minimal.\n\n---\n\n### FASTAPI-CSRF-001: Cookie-authenticated state-changing requests MUST be CSRF-protected\n\nSeverity: High\n\nNote: This only applies if using cookie based auth. If the application uses header or token based auth such as Authorization header, then CSRF is not an issue.\n\nRequired:\n\n* MUST protect all state-changing endpoints (POST/PUT/PATCH/DELETE) that rely on cookies for authentication.\n* SHOULD use a proven CSRF approach (synchronizer token pattern, or well-reviewed middleware) rather than rolling your own. ([OWASP Cheat Sheet Series][2])\n* MAY add defense-in-depth (Origin/Referer checks, SameSite cookies, Fetch Metadata), but tokens are the primary defense for cookie-authenticated apps. ([OWASP Cheat Sheet Series][2])\n* IMPORTANT NOTE: If cookies are not used for auth (auth is via `Authorization` header), CSRF is usually not applicable. ([FastAPI][11])\n\nInsecure patterns:\n\n* Cookie-authenticated endpoints that change state with no CSRF validation.\n* Using GET for state-changing actions (amplifies CSRF risk).\n\nDetection hints:\n\n* Enumerate routes with methods other than GET; identify whether cookies are used for auth.\n* Look for CSRF token generation/verification or middleware.\n\nFix:\n\n* Add CSRF tokens (and validate them) on state-changing actions when cookie auth is in use. ([OWASP Cheat Sheet Series][2])\n\n---\n\n### FASTAPI-VALID-001: Request parsing and validation MUST be schema-driven; prevent mass assignment\n\nSeverity: Medium (especially for APIs that write to DB)\n\nRequired:\n\n* SHOULD use Pydantic models for request bodies instead of accepting arbitrary `dict`/`Any`.\n* SHOULD configure models to reject unexpected fields where appropriate (prevents “mass assignment” style bugs).\n* MUST validate and normalize identifiers (IDs, email, URLs) before using them for access control or side effects. ([OWASP Cheat Sheet Series][14])\n\nInsecure patterns:\n\n* `payload = await request.json()` followed by `Model(**payload)` or direct DB writes with `payload` (no allowlist).\n* Models that silently accept unknown fields for write endpoints.\n\nDetection hints:\n\n* Search for `await request.json()`, `request.body()`, `dict`-typed bodies, `Any`-typed bodies.\n* Look for endpoints that do `db.update(**payload)` or `Model(**payload)` with unfiltered input.\n\nFix:\n\n* Use explicit Pydantic models with allowlisted fields; reject extras for write endpoints. ([OWASP Cheat Sheet Series][14])\n\n---\n\n### FASTAPI-RESP-001: Prevent excessive data exposure via response models and explicit serialization\n\nSeverity: Medium\n\nRequired:\n\n* MUST define response models that include only intended fields (especially for user objects, auth-related objects, billing objects).\n* SHOULD use separate models for “create input”, “db/internal”, and “public output” to avoid leaking sensitive fields. ([FastAPI][15])\n\nInsecure patterns:\n\n* Returning ORM objects or dicts that include internal columns.\n* Reusing “DB model” as the response model (includes `password_hash`, `is_admin`, etc).\n\nDetection hints:\n\n* Look for endpoints that `return user` where `user` is an ORM instance.\n* Check for `response_model` omissions on endpoints that return sensitive resources.\n\nFix:\n\n* Add explicit response models; create “public” schemas that exclude sensitive fields. ([FastAPI][15])\n\n---\n\n### FASTAPI-XSS-001: Prevent reflected/stored XSS in HTML responses and templates\n\nSeverity: High (if the service serves HTML)\n\nRequired:\n\n* MUST use templating with auto-escaping enabled for HTML.\n* MUST NOT mark untrusted content as safe (no unsafe “raw HTML” rendering of user-controlled data).\n* SHOULD deploy a CSP when serving HTML that includes any user content. ([OWASP Cheat Sheet Series][16])\n\nInsecure patterns:\n\n* Rendering user content directly into HTML without escaping/sanitization.\n* Disabling auto-escaping or using “raw HTML” features without sanitization.\n\nDetection hints:\n\n* Search for template rendering and string concatenation that builds HTML.\n* Review templates for “unsafe” filters/constructs and unquoted attributes.\n\nFix:\n\n* Keep auto-escaping on; sanitize user HTML only if absolutely required using a trusted sanitizer; add CSP. ([OWASP Cheat Sheet Series][16])\n\nNote:\n\n* If the app is a pure JSON API, XSS is usually a client/app concern, but error pages/docs pages might still render HTML.\n\n---\n\n### FASTAPI-SSTI-001: Never render untrusted templates (Server-Side Template Injection)\n\nSeverity: Critical\n\nRequired:\n\n* MUST NOT render templates that contain user-controlled template syntax.\n* MUST treat “template-from-string” rendering as dangerous if influenced by untrusted input.\n* If untrusted templates are absolutely required (rare, high-risk):\n\n  * MUST use a sandboxed templating approach and restrict capabilities.\n  * MUST assume sandbox escapes are possible; add isolation and strict allowlists. ([OWASP Foundation][17])\n\nInsecure patterns:\n\n* Rendering templates loaded from user input or DB via a normal Jinja environment.\n* Building templates dynamically using user-controlled strings.\n\nDetection hints:\n\n* Grep for Jinja `Environment.from_string`, `Template(...)`, or similar.\n* Trace origin of template string (request, DB, uploads, admin panels).\n\nFix:\n\n* Replace with non-executable templating (simple string substitution).\n* If truly needed, use Jinja’s sandbox environment plus strong isolation. ([jinja.palletsprojects.com][18])\n\n---\n\n### FASTAPI-HEADERS-001: Set essential security headers (in app or at the edge)\n\nSeverity: Medium\n\nRequired (typical API/web app):\n\n* SHOULD set:\n\n  * `X-Content-Type-Options: nosniff`\n  * Clickjacking protection (`X-Frame-Options` and/or CSP `frame-ancestors`) if HTML is served\n  * `Referrer-Policy` and `Permissions-Policy` as appropriate\n\nNOTE:\n\n* Headers may be set by a proxy/CDN. If not visible in app code, flag as “verify at edge”. ([OWASP Cheat Sheet Series][6])\n\nInsecure patterns:\n\n* No security headers anywhere (app or edge) for apps serving HTML or sensitive APIs.\n\nDetection hints:\n\n* Search for middleware that sets headers; check reverse proxy config.\n\nFix:\n\n* Set headers centrally (middleware) or via reverse proxy/CDN.\n\n---\n\n### FASTAPI-CORS-001: CORS MUST be explicit and least-privilege\n\nSeverity: Medium (High if misconfigured with credentials)\n\nRequired:\n\n* If CORS is not needed, MUST keep it disabled.\n* If CORS is needed:\n\n  * MUST allowlist trusted origins (do not reflect arbitrary origins).\n  * MUST NOT combine credentialed requests with wildcard origins (this is unsafe and commonly rejected by compliant middleware). ([OWASP Cheat Sheet Series][6])\n  * SHOULD restrict allowed methods and headers.\n\nInsecure patterns:\n\n* `allow_origins=[\"*\"]` together with `allow_credentials=True`.\n* Reflecting `Origin` without validation.\n* `allow_origin_regex=\".*\"` used broadly.\n\nDetection hints:\n\n* Search for `CORSMiddleware` configuration.\n* Look for `allow_origins=[\"*\"]`, `allow_credentials=True`, `allow_origin_regex`.\n\nFix:\n\n* Use an explicit origin allowlist and minimal methods/headers; keep credentials off unless required. ([OWASP Cheat Sheet Series][6])\n\n---\n\n### FASTAPI-HOST-001: Host header MUST be validated in production\n\nSeverity: Low\n\nRequired:\n\n* SHOULD use `TrustedHostMiddleware` (or equivalent at edge) to restrict accepted Host values. ([PyPI][5])\n* MUST NOT trust the `Host` header for security-sensitive decisions without validation.\n\nInsecure patterns:\n\n* No Host validation while generating external URLs (password reset links, callback URLs) from request host.\n* Allowing arbitrary Host headers in apps behind permissive proxies.\n\nDetection hints:\n\n* Search for `TrustedHostMiddleware` usage.\n* Search for logic that uses `request.url`, `request.base_url`, or host-derived values to build external URLs.\n\nFix:\n\n* Configure a strict allowed-hosts list in production; enforce at edge too if possible.\n\n---\n\n### FASTAPI-PROXY-001: Reverse proxy trust MUST be configured correctly\n\nSeverity: High (when behind a proxy)\n\nRequired:\n\n* If behind a reverse proxy, MUST configure forwarded-header trust correctly.\n* MUST NOT blindly trust `X-Forwarded-*` headers from the open internet.\n* If using Uvicorn proxy header support, MUST restrict which IPs are allowed to provide forwarded headers. ([PyPI][4])\n\nInsecure patterns:\n\n* Enabling proxy headers broadly without restricting trusted proxy IPs.\n* Using forwarded headers to decide “is secure” / “is internal” / “client IP” without proper trust boundaries.\n\nDetection hints:\n\n* Search for `--proxy-headers`, `--forwarded-allow-ips`, or equivalent config.\n* Search for security-sensitive use of `request.client.host`, `request.url.scheme`, `request.headers[\"x-forwarded-for\"]`.\n\nFix:\n\n* Configure Uvicorn with proxy headers only when behind a known proxy, and restrict `forwarded_allow_ips` to that proxy. ([PyPI][4])\n* Keep Host allowlisting in place even behind proxies.\n\n---\n\n### FASTAPI-LIMITS-001: Request and multipart limits MUST be enforced to prevent DoS\n\nSeverity: Low\n\nRequired:\n\n* MUST enforce request size limits at the edge (reverse proxy/load balancer) and validate in app where needed.\n* MUST apply special scrutiny to multipart/form-data handling; historical vulnerabilities include unbounded buffering and DoS vectors. ([advisories.gitlab.com][9])\n* SHOULD rate limit and/or add per-IP/per-user throttles for expensive endpoints.\n\nInsecure patterns:\n\n* Accepting arbitrarily large JSON bodies or multipart forms.\n* Parsing multipart forms without size/field-count controls.\n\nDetection hints:\n\n* Identify file upload endpoints and `multipart/form-data` usage.\n* Look for missing proxy-level limits (nginx `client_max_body_size`, ALB limits, etc.) and missing app-level checks.\n\nFix:\n\n* Enforce strict body limits and multipart constraints; keep Starlette and python-multipart updated to patched versions. ([advisories.gitlab.com][9])\n\n---\n\n### FASTAPI-FILES-001: Prevent path traversal and unsafe static file exposure\n\nSeverity: High\n\nRequired:\n\n* MUST NOT pass user-controlled file paths to `FileResponse`/filesystem calls without strict validation and safe base directories.\n* If using `StaticFiles`, MUST keep Starlette updated and understand the security history (path traversal advisory exists for older versions). ([advisories.gitlab.com][10])\n* MUST NOT serve user uploads as executable/active content (especially HTML/JS) from a static root without safe handling.\n\nInsecure patterns:\n\n* `FileResponse(request.query_params[\"path\"])`\n* Mounting `StaticFiles(directory=\"uploads\")` where uploads include HTML/JS/SVG and are served inline.\n\nDetection hints:\n\n* Search for `FileResponse(`, `StaticFiles(`, `open(` in routes.\n* Trace whether the path originates from untrusted input.\n\nFix:\n\n* Use opaque IDs for files; map IDs to server-side stored paths.\n* Serve untrusted content as attachment downloads where appropriate.\n\n---\n\n### FASTAPI-FILES-002: Mitigate Range-header DoS on file-serving endpoints\n\nSeverity: Low (if affected versions and file serving is enabled)\n\nRequired:\n\n* MUST keep Starlette patched against known file-serving DoS issues if using `FileResponse`/`StaticFiles`.\n* MUST treat unusual `Range` header handling and file serving as a DoS surface. ([advisories.gitlab.com][19])\n\nInsecure patterns:\n\n* Serving large files with vulnerable Starlette versions.\n* No rate limiting / CDN shielding for file endpoints.\n\nDetection hints:\n\n* Identify Starlette version; if in affected range, flag.\n* Find uses of `FileResponse` and `StaticFiles`.\n\nFix:\n\n* Upgrade Starlette to a fixed version per advisory guidance. ([advisories.gitlab.com][19])\n* Add edge caching/rate limiting for file endpoints where appropriate.\n\n---\n\n### FASTAPI-UPLOAD-001: File uploads MUST be validated, stored safely, and served safely\n\nSeverity: Medium\n\nRequired:\n\n* MUST enforce upload size limits (app + edge).\n* MUST validate file type using allowlists and content checks (not only extension). ([OWASP Cheat Sheet Series][20])\n* SHOULD generate server-side filenames (random IDs) and avoid trusting original names.\n* MUST serve potentially active formats safely (download attachment) unless explicitly intended.\n\nInsecure patterns:\n\n* Accepting arbitrary file types and serving them back inline.\n* Using user-supplied filename as storage path.\n\nDetection hints:\n\n* Look for upload handlers and where/how files are written.\n* Look for direct exposure of upload directories.\n\nFix:\n\n* Implement allowlist validation + safe storage + safe serving; add scanning/quarantine if applicable. ([OWASP Cheat Sheet Series][20])\n\n---\n\n### FASTAPI-INJECT-001: Prevent SQL injection (use parameterized queries / ORM)\n\nSeverity: High\n\nRequired:\n\n* MUST use parameterized queries or an ORM that parameterizes under the hood.\n* MUST NOT build SQL by string concatenation / f-strings with untrusted input. ([OWASP Cheat Sheet Series][21])\n\nInsecure patterns:\n\n* `f\"SELECT ... WHERE id={user_id}\"`\n* `\"... WHERE name = '%s'\" % user_input`\n\nDetection hints:\n\n* Grep for SQL keywords in Python strings near `.execute(...)`.\n* Trace untrusted data into DB calls.\n\nFix:\n\n* Replace with parameterized queries / ORM query APIs; validate types before querying. ([OWASP Cheat Sheet Series][21])\n\n---\n\n### FASTAPI-INJECT-002: Prevent OS command injection\n\nSeverity: Critical to High (depends on exposure)\n\nRequired:\n\n* MUST avoid executing shell commands with untrusted input.\n* If subprocess is necessary:\n\n  * MUST pass args as a list (not a string)\n  * MUST NOT use `shell=True` with attacker-influenced strings\n  * SHOULD use strict allowlists for any variable component ([OWASP Cheat Sheet Series][22])\n\nInsecure patterns:\n\n* `os.system(user_input)`\n* `subprocess.run(f\"cmd {user}\", shell=True)`\n* Passing user strings into `bash -c`, `sh -c`, PowerShell, etc.\n\nDetection hints:\n\n* Search for `os.system`, `subprocess`, `Popen`, `shell=True`.\n* Trace data from request/DB into these calls.\n\nFix:\n\n* Use library APIs instead of shell commands.\n* If unavoidable, hard-code the command and allowlist validated parameters; use `--` separator where supported. ([OWASP Cheat Sheet Series][22])\n\n---\n\n### FASTAPI-SSRF-001: Prevent server-side request forgery (SSRF) in outbound HTTP\n\nSeverity: Medium (can be High in cloud/VPC environments)\n\n- Note: For small stand alone projects this is less important. It is most important when deploying into an LAN or with other services listening on the same server.\n\nRequired:\n\n* MUST treat outbound requests to user-provided URLs as high risk.\n* SHOULD validate and restrict destinations (allowlist hosts/domains) for any user-influenced URL fetch.\n* SHOULD block access to localhost/private IP ranges/link-local and cloud metadata endpoints.\n* MUST restrict protocols to http/https.\n* SHOULD set timeouts and carefully control redirects. ([OWASP Cheat Sheet Series][23])\n\nInsecure patterns:\n\n* `httpx.get(request.query_params[\"url\"])`\n* “URL preview/import/webhook tester” features that accept arbitrary URLs.\n\nDetection hints:\n\n* Search for `requests`, `httpx`, `urllib`, `aiohttp` calls with URLs derived from requests/DB.\n* Identify endpoints named `fetch`, `preview`, `proxy`, `webhook`, `import`.\n\nFix:\n\n* Implement strict URL parsing + allowlists; add egress controls; set short timeouts; disable redirects if not required. ([OWASP Cheat Sheet Series][23])\n\n---\n\n### FASTAPI-REDIRECT-001: Prevent open redirects\n\nSeverity: Low\n\nRequired:\n\n* MUST validate redirect targets derived from untrusted input (`next`, `redirect`, `return_to`).\n* SHOULD prefer redirecting only to same-site relative paths or an allowlist of domains. ([OWASP Cheat Sheet Series][24])\n\nInsecure patterns:\n\n* Returning `RedirectResponse(next)` where `next` is user-controlled with no validation.\n\nDetection hints:\n\n* Search for `RedirectResponse(` or redirect logic and examine the source of the target.\n\nFix:\n\n* Allow only relative paths or allowlisted domains; fall back to a safe default. ([OWASP Cheat Sheet Series][24])\n\n---\n\n### FASTAPI-WS-001: WebSocket endpoints MUST be authenticated and protected against cross-site abuse\n\nSeverity: Medium to High (depends on data/privilege)\n\nRequired:\n\n* MUST authenticate WebSocket connections for any non-public channel (WebSockets don’t inherently provide auth). ([OWASP Cheat Sheet Series][25])\n* SHOULD enforce origin/CSRF-like protections appropriate for browser-based WebSocket clients (Origin validation is a common control).\n* SHOULD rate limit message frequency and connection attempts; close idle/abusive connections.\n\nInsecure patterns:\n\n* `@app.websocket(...)` accepts and trusts the connection with no auth check.\n* Using query-string tokens for auth without considering leakage/rotation.\n\nDetection hints:\n\n* Search for `@app.websocket` / `websocket_endpoint` and inspect whether auth is performed before accepting sensitive operations.\n* Review origin checks, token parsing, and per-connection authorization.\n\nFix:\n\n* Require authentication during handshake (e.g., a token or session) and enforce authorization for actions/messages.\n* Validate Origin for browser-based clients where appropriate; apply rate limits and timeouts. ([OWASP Cheat Sheet Series][25])\n\n---\n\n### FASTAPI-SUPPLY-001: Dependency and patch hygiene (focus on security-relevant deps)\n\nSeverity: Low\n\nRequired:\n\n* SHOULD pin and regularly update security-critical dependencies (FastAPI, Starlette, Uvicorn, Pydantic, python-multipart, auth/JWT libs).\n* MUST respond to known security advisories promptly.\n* MUST treat file serving and multipart parsing dependencies as security-sensitive due to historical CVEs. ([advisories.gitlab.com][10])\n\nAudit focus examples (historical):\n\n* Starlette StaticFiles path traversal (fixed in 0.27.0). ([advisories.gitlab.com][10])\n* Starlette multipart/form-data DoS (fixed in 0.40.0). ([advisories.gitlab.com][9])\n* Starlette FileResponse Range header DoS (fixed in 0.49.1). ([advisories.gitlab.com][19])\n\nDetection hints:\n\n* Check `requirements.txt`, lockfiles, container images, and runtime environments for actual installed versions.\n* Map file upload/file serving features to dependency versions.\n\nFix:\n\n* Upgrade to patched versions per advisories; add regression tests around affected behavior.\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* Dev server / debug:\n\n  * `--reload`, `reload=True`, `debug=True`, `FastAPI(debug=True)` ([PyPI][4])\n* OpenAPI/docs exposure:\n\n  * `/docs`, `/redoc`, `/openapi.json`, `docs_url=`, `openapi_url=`\n* Auth enforcement gaps:\n\n  * Endpoints missing `Depends()`/`Security()` where expected; routers without a consistent dependency boundary ([FastAPI][7])\n  * Tokens in query params (`token=`, `api_key=`, `key=`) ([FastAPI][11])\n* Session/cookies + CSRF:\n\n  * `SessionMiddleware(` and cookie flags (`https_only`, `same_site`) ([PyPI][5])\n  * POST/PUT/PATCH/DELETE handlers using cookie auth with no CSRF checks ([OWASP Cheat Sheet Series][2])\n* Input validation & mass assignment:\n\n  * `await request.json()` and direct DB writes from dicts; models accepting extra fields ([OWASP Cheat Sheet Series][14])\n* Excessive data exposure:\n\n  * Returning ORM objects or dicts without `response_model`; responses containing password/role/internal fields ([FastAPI][15])\n* CORS:\n\n  * `CORSMiddleware` with `allow_origins=[\"*\"]`, `allow_origin_regex=\".*\"`, `allow_credentials=True` ([OWASP Cheat Sheet Series][6])\n* Files:\n\n  * `FileResponse(` with user-controlled paths; `StaticFiles(` exposing uploads ([advisories.gitlab.com][10])\n* Uploads / multipart:\n\n  * `multipart/form-data` endpoints with no size/field constraints; outdated Starlette/python-multipart ([advisories.gitlab.com][9])\n* Injection:\n\n  * SQL strings with f-strings/concatenation into `.execute(...)` ([OWASP Cheat Sheet Series][21])\n  * `subprocess.*`, `shell=True`, `os.system` ([OWASP Cheat Sheet Series][22])\n* SSRF:\n\n  * `httpx.get/post` or `requests.*` with URL from request/DB, no allowlist/timeouts ([OWASP Cheat Sheet Series][23])\n* Redirect:\n\n  * `RedirectResponse(next)` with no validation ([OWASP Cheat Sheet Series][24])\n* WebSockets:\n\n  * `@app.websocket` handlers without auth/origin checks; use of `ws://` in prod configs ([FastAPI][27])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (SQL/subprocess/files/template/http/redirect/ws)\n* protective controls present (validation, allowlists, middleware, edge controls)\n* installed dependency versions vs vulnerable ranges ([advisories.gitlab.com][10])\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary framework documentation:\n\n* FastAPI (PyPI metadata, versioning) — `https://pypi.org/project/fastapi/` ([PyPI][1])\n* FastAPI docs: Security “First Steps” (Authorization Bearer header conventions) — `https://fastapi.tiangolo.com/tutorial/security/first-steps/` ([FastAPI][11])\n* FastAPI reference: Dependencies (`Depends`, `Security`) — `https://fastapi.tiangolo.com/reference/dependencies/` ([FastAPI][7])\n* FastAPI reference: APIRouter (router-level dependencies) — `https://fastapi.tiangolo.com/reference/apirouter/` ([FastAPI][28])\n* FastAPI docs: WebSockets — `https://fastapi.tiangolo.com/advanced/websockets/` ([FastAPI][27])\n\nASGI/server stack documentation:\n\n* Starlette (PyPI, general capabilities) — `https://pypi.org/project/starlette/` ([PyPI][5])\n* Starlette docs: WebSockets — `https://starlette.dev/websockets/` ([Starlette][3])\n* Uvicorn (PyPI metadata) — `https://pypi.org/project/uvicorn/` ([PyPI][4])\n* Pydantic docs (v2.12.x) — `https://docs.pydantic.dev/latest/` ([Pydantic][29])\n\nSecurity standards and cheat sheets:\n\n* OWASP Cheat Sheet Series: Session Management — `https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][8])\n* OWASP Cheat Sheet Series: CSRF Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][2])\n* OWASP Cheat Sheet Series: XSS Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][16])\n* OWASP Cheat Sheet Series: Mass Assignment — `https://cheatsheetseries.owasp.org/cheatsheets/Mass_Assignment_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][14])\n* OWASP API Security Top 10 (2023) — `https://owasp.org/API-Security/editions/2023/en/0x11-t10/` ([OWASP Foundation][13])\n* OWASP Cheat Sheet Series: SQL Injection Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][21])\n* OWASP Cheat Sheet Series: OS Command Injection Defense — `https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][22])\n* OWASP Cheat Sheet Series: SSRF Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][23])\n* OWASP Cheat Sheet Series: File Upload — `https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][20])\n* OWASP Cheat Sheet Series: Unvalidated Redirects and Forwards — `https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][24])\n* OWASP Cheat Sheet Series: HTTP Security Response Headers — `https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][6])\n* OWASP Cheat Sheet Series: WebSocket Security — `https://cheatsheetseries.owasp.org/cheatsheets/WebSocket_Security_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][25])\n* OWASP WSTG: Testing for Server-Side Template Injection — `https://owasp.org/www-project-web-security-testing-guide/v41/4-Web_Application_Security_Testing/07-Input_Validation_Testing/18-Testing_for_Server_Side_Template_Injection` ([OWASP Foundation][17])\n* OWASP WSTG: Testing WebSockets — `https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/11-Client-side_Testing/10-Testing_WebSockets` ([OWASP Foundation][26])\n\nTemplate safety references:\n\n* Jinja: Sandbox — `https://jinja.palletsprojects.com/en/stable/sandbox/` ([jinja.palletsprojects.com][18])\n\nSelected supply-chain/advisory references (Starlette examples):\n\n* CVE-2023-29159 (StaticFiles path traversal; fixed 0.27.0) — `https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2023-29159/` ([advisories.gitlab.com][10])\n* CVE-2024-47874 (multipart/form-data DoS; fixed 0.40.0) — `https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2024-47874/` ([advisories.gitlab.com][9])\n* CVE-2025-62727 (FileResponse Range header DoS; fixed 0.49.1) — `https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2025-62727/` ([advisories.gitlab.com][19])\n\n[1]: https://pypi.org/project/fastapi/ \"https://pypi.org/project/fastapi/\"\n[2]: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html\"\n[3]: https://starlette.dev/websockets/?utm_source=chatgpt.com \"Websockets\"\n[4]: https://pypi.org/project/uvicorn/ \"https://pypi.org/project/uvicorn/\"\n[5]: https://pypi.org/project/starlette/ \"https://pypi.org/project/starlette/\"\n[6]: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html?utm_source=chatgpt.com \"HTTP Security Response Headers Cheat Sheet\"\n[7]: https://fastapi.tiangolo.com/reference/dependencies/?utm_source=chatgpt.com \"Dependencies - Depends() and Security() - FastAPI\"\n[8]: https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html\"\n[9]: https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2024-47874/ \"Starlette Denial of service (DoS) via multipart/form-data | GitLab Advisory Database\"\n[10]: https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2023-29159/ \"Starlette has Path Traversal vulnerability in StaticFiles | GitLab Advisory Database\"\n[11]: https://fastapi.tiangolo.com/tutorial/security/first-steps/?utm_source=chatgpt.com \"Security - First Steps - FastAPI\"\n[12]: https://fastapi.tiangolo.com/tutorial/response-model/ \"https://fastapi.tiangolo.com/tutorial/response-model/\"\n[13]: https://owasp.org/API-Security/editions/2023/en/0x11-t10/ \"https://owasp.org/API-Security/editions/2023/en/0x11-t10/\"\n[14]: https://cheatsheetseries.owasp.org/cheatsheets/Mass_Assignment_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Mass_Assignment_Cheat_Sheet.html\"\n[15]: https://fastapi.tiangolo.com/tutorial/extra-models/ \"https://fastapi.tiangolo.com/tutorial/extra-models/\"\n[16]: https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html\"\n[17]: https://owasp.org/www-project-web-security-testing-guide/v41/4-Web_Application_Security_Testing/07-Input_Validation_Testing/18-Testing_for_Server_Side_Template_Injection?utm_source=chatgpt.com \"Testing for Server Side Template Injection\"\n[18]: https://jinja.palletsprojects.com/en/stable/sandbox/?utm_source=chatgpt.com \"Sandbox — Jinja Documentation (3.1.x)\"\n[19]: https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2025-62727/ \"Starlette vulnerable to O(n^2) DoS via Range header merging in ``starlette.responses.FileResponse`` | GitLab Advisory Database\"\n[20]: https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html\"\n[21]: https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html\"\n[22]: https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html\"\n[23]: https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html\"\n[24]: https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html?utm_source=chatgpt.com \"Unvalidated Redirects and Forwards Cheat Sheet\"\n[25]: https://cheatsheetseries.owasp.org/cheatsheets/WebSocket_Security_Cheat_Sheet.html?utm_source=chatgpt.com \"WebSocket Security - OWASP Cheat Sheet Series\"\n[26]: https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/11-Client-side_Testing/10-Testing_WebSockets?utm_source=chatgpt.com \"WSTG - Latest | OWASP Foundation\"\n[27]: https://fastapi.tiangolo.com/advanced/websockets/?utm_source=chatgpt.com \"WebSockets - FastAPI\"\n[28]: https://fastapi.tiangolo.com/reference/apirouter/?utm_source=chatgpt.com \"APIRouter class - FastAPI\"\n[29]: https://docs.pydantic.dev/latest/ \"https://docs.pydantic.dev/latest/\"\n","core/skills/builtin/security-best-practices/references/python-flask-web-server-security.md":"# Flask (Python) Web Security Spec (Flask 3.1.x, Python 3.x)\n\nThis document is designed as a **security spec** that supports:\n1) **Secure-by-default code generation** for new Flask code.\n2) **Security review / vulnerability hunting** in existing Flask code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n--------------------------------------------------------------------\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n- MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session cookies, SECRET_KEY).\n- MUST NOT “fix” security by disabling protections (e.g., turning off CSRF, relaxing CORS, disabling escaping, disabling auth checks).\n- MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and configuration values that justify the claim.\n- MUST treat uncertainty honestly: if a protection might exist in infrastructure (reverse proxy, WAF, CDN), report it as “not visible in app code; verify at runtime/config”.\n\n--------------------------------------------------------------------\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\nWhen asked to write new Flask code or modify existing code:\n- MUST follow every **MUST** requirement in this spec.\n- SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n- MUST prefer safe-by-default APIs and proven libraries over custom security code.\n- MUST avoid introducing new risky sinks (template rendering from strings, shell execution, dynamic imports, unsafe redirects, serving user files as HTML, etc.).\n\n### 1.2 Passive review mode (always on while editing)\nWhile working anywhere in a Flask repo (even if the user did not ask for a security scan):\n- MUST “notice” violations of this spec in touched/nearby code.\n- SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n- MUST systematically search the codebase for violations of this spec.\n- MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n1) App entrypoints / deployment scripts / Dockerfiles / Procfiles.\n2) Flask configuration and environment handling.\n3) Auth + sessions + cookies.\n4) CSRF protections and state-changing routes.\n5) Template rendering and XSS/SSTI.\n6) File handling (uploads + downloads) and path traversal.\n7) Injection classes (SQL, command execution, unsafe deserialization).\n8) Outbound requests (SSRF).\n9) Redirect handling (open redirects).\n10) CORS and security headers.\n\n--------------------------------------------------------------------\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\nExamples include:\n- `request.args`, `request.form`, `request.values`\n- `request.get_json()`, `request.json`, `request.data`\n- `request.headers`, `request.cookies`\n- URL path parameters (e.g., `/user/<id>`)\n- Any data from external systems (webhooks, third-party APIs, message queues)\n- Any persisted user content (DB rows) that originated from users\n\n### 2.2 State-changing request\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook send), or initiate privileged actions.\n\n### 2.3 Required audit finding format\nFor each issue found, output:\n\n- Rule ID:\n- Severity: Critical / High / Medium / Low\n- Location: file path + function/route name + line(s)\n- Evidence: the exact code/config snippet\n- Impact: what could go wrong, who can exploit it\n- Fix: safe change (prefer minimal diff)\n- Mitigation: defense-in-depth if immediate fix is hard\n- False positive notes: what to verify if uncertain\n\n--------------------------------------------------------------------\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common Flask misconfigurations.\n\n### 3.1 App initialization pattern (SHOULD)\nSHOULD use an app factory and environment-based config so production config is not hard-coded.\n\nExample skeleton (illustrative; adjust to your project):\n- Load config from environment / secret store.\n- Fail closed if critical settings are missing in production.\n\nKey baseline config targets:\n- `SECRET_KEY` set and not committed\n- `SESSION_COOKIE_SECURE=True` (when HTTPS) IMPORTANT NOTE: Only set `Secure` in production environment when TLS is configured. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n- `SESSION_COOKIE_HTTPONLY=True`\n- `SESSION_COOKIE_SAMESITE='Lax'` (or `'Strict'` if compatible)\n- `TRUSTED_HOSTS` set in production\n- Security headers set (CSP, etc.) either in app or at the edge\n\n--------------------------------------------------------------------\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### FLASK-DEPLOY-001: Do not use Flask’s development server in production\nSeverity: High (if production)\n\nRequired:\n- MUST NOT deploy the built-in development server as the production server.\n- MUST run behind a production-grade WSGI server or managed platform (such as gunicorn)\n\nInsecure patterns:\n- `app.run(...)` in a production entrypoint.\n- Deployment docs/scripts that use `flask run` in production.\n\nDetection hints:\n- Search for `app.run(`, `flask run`, `--debug`, `FLASK_DEBUG`, `FLASK_ENV=development`.\n- Check Docker CMD/ENTRYPOINT, Procfile, systemd units, shell scripts.\n\nFix:\n- Use a production WSGI server (and keep Flask as the app object).\n- Ensure the dev server is only used for local development.\n\nNote:\n- These are often used in dev mode or local testing. This is allowed. Only flag if it is clear that it is being used as the production entrypoint\n\n---\n\n### FLASK-DEPLOY-002: Debug mode MUST be disabled in production\nSeverity: Critical\n\nRequired:\n- MUST NOT enable debug mode in production.\n- MUST treat the interactive debugger as equivalent to remote code execution if exposed.\n\nInsecure patterns:\n- `app.run(debug=True)`\n- `flask run --debug` in production.\n- `DEBUG=True` via env/config in production.\n\nDetection hints:\n- Look for `debug=True`, `FLASK_DEBUG=1`, `DEBUG = True`, `app.debug = True`.\n- Look for `TRAP_HTTP_EXCEPTIONS`/debugger settings enabled in non-test contexts.\n\nFix:\n- Ensure debug is only enabled in local dev/test.\n- Prefer environment-based toggles and safe defaults.\n\nNote:\n- These are often used in dev mode or local testing. This is allowed. Only flag if it is clear that it is being used as the production entrypoint\n\n---\n\n### FLASK-CONFIG-001: SECRET_KEY must be strong, secret, and rotated safely\nSeverity: High (Critical if missing in production with sessions or signing)\n\nRequired:\n- MUST set a strong random `SECRET_KEY` in production.\n- MUST keep `SECRET_KEY` out of source control and out of logs.\n- MAY rotate keys periodically; MAY use `SECRET_KEY_FALLBACKS` to support rotation without instantly invalidating existing sessions, then remove old keys after the rotation window. This likely is not needed for smaller applications but is good practice for larger applications. As this may complicate deployment, suggest that it be implemented rather than implementing it by default.\n\nInsecure patterns:\n- Missing `SECRET_KEY` in production.\n- Hard-coded `SECRET_KEY` in repo (including test keys accidentally used in prod).\n- Logging or printing `SECRET_KEY`.\n\nDetection hints:\n- Search for `SECRET_KEY =`, `app.secret_key =`, `SECRET_KEY_FALLBACKS =`.\n- Check `.env` files committed to repo.\n- Check config modules for constants.\n\nFix:\n- Load from secret manager or environment variable.\n- Add a rotation process:\n  - Set new `SECRET_KEY`\n  - Keep old key(s) temporarily in `SECRET_KEY_FALLBACKS`\n  - Remove old key(s) after the safe window.\n\nNotes:\n- If the application uses Flask sessions (cookie-based by default), `SECRET_KEY` is directly security-critical.\n\n---\n\n### FLASK-SESS-001: Session cookies must use secure attributes in production\nSeverity: Medium\n\nRequired (production, HTTPS):\n- MUST set `SESSION_COOKIE_SECURE=True` (cookies only over HTTPS). NOTE: Only set `Secure` in production environment when TLS is configured. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n- MUST ensure `SESSION_COOKIE_HTTPONLY=True` (protect from JS access).\n- SHOULD set `SESSION_COOKIE_SAMESITE='Lax'` (recommended) or `'Strict'` if compatible with UX.\n- SHOULD keep `SESSION_COOKIE_DOMAIN=None` unless you explicitly need subdomain-wide cookies.\n- If you need embedded/iframe third-party usage, MAY consider `SESSION_COOKIE_PARTITIONED=True` (requires HTTPS).\n\nInsecure patterns:\n- `SESSION_COOKIE_SECURE=False` in production.\n- `SESSION_COOKIE_HTTPONLY=False`.\n- `SESSION_COOKIE_SAMESITE=None` with cookie-authenticated state-changing endpoints (higher CSRF risk).\n\nDetection hints:\n- Inspect `app.config.update(...)` blocks and config classes.\n- Look for `set_cookie(..., secure=..., httponly=..., samesite=...)` usage on non-session cookies too.\n\nFix:\n- Set these config values explicitly in production config.\n\nNotes:\n- SameSite is defense-in-depth; do not treat it as a full replacement for CSRF tokens.\n\n---\n\n### FLASK-SESS-002: Sessions must be bounded and resistant to fixation/replay\nSeverity: Medium\n\nRequired:\n- SHOULD set a bounded session lifetime appropriate to the app.\n- SHOULD set `session.permanent = True` only when you intend persistent sessions, and set `PERMANENT_SESSION_LIFETIME` to a justified value.\n- SHOULD clear the session on login and privilege changes to reduce session fixation risk.\n- MUST NOT store sensitive secrets in the default Flask session cookie. The default session is signed, not encrypted.\n\nInsecure patterns:\n- Extremely long or unlimited lifetimes for privileged sessions.\n- No session clearing on login.\n- Storing secrets (passwords, access tokens, PII) directly in `session[...]` when using default cookie sessions.\n\nDetection hints:\n- Search for `PERMANENT_SESSION_LIFETIME`, `session.permanent`, `session[...] =`.\n- Identify whether server-side session storage is used; if not, assume default cookie sessions.\n\nFix:\n- Set appropriate lifetimes.\n- Clear/rotate session on login.\n- Store sensitive data server-side; store only identifiers in the session cookie.\n\n---\n\n### FLASK-CSRF-001: State-changing requests using cookie auth MUST be CSRF-protected\nSeverity: High\n\n- IMPORTANT NOTE: If cookies are not being used for auth (ie auth is via Authentication header or other passed token), then there is no CSRF risk.\n\nRequired:\n- MUST protect all state-changing endpoints (POST/PUT/PATCH/DELETE) that rely on cookies for authentication.\n- MAY use a well-tested CSRF library/integration (form framework or middleware) rather than rolling your own.\n- MAY use additional defenses (Origin/Referer checking, SameSite cookies, Fetch Metadata headers, custom headers for AJAX/API), but tokens remain the primary defense for cookie-authenticated apps.\nIf tokens are impractical, or for small applications:\n* MUST at a minimum require a custom header to be set and set the session cookie SESSION_COOKIE_SAMESITE=lax, as this is the strongest method besides requiring a form token, and may be much easier to implement.\n\nInsecure patterns:\n- Cookie-authenticated endpoints that change state with no CSRF protection.\n- Using GET for state-changing actions (amplifies CSRF risk).\n\nDetection hints:\n- Enumerate routes with methods other than GET and identify auth mechanism.\n- Look for CSRF integrations (e.g., Flask-WTF, global CSRF middleware). If absent, treat as suspicious.\n- Check JSON API endpoints too, not only HTML forms.\n\nFix:\n- Add CSRF protection to all state-changing requests.\n- If the app is a pure API and uses Authorization headers (bearer tokens) rather than cookies, document that choice and ensure cookies aren’t used for auth. If cookies are not used for auth, there is no CSRF risk.\n\nNotes:\n- XSS can defeat CSRF protections; CSRF defenses do not replace XSS prevention.\n\n---\n\n### FLASK-XSS-001: Prevent reflected/stored XSS in templates and HTML generation\nSeverity: High\n\nRequired:\n- MUST rely on Jinja auto-escaping for HTML templates.\n- MUST NOT mark untrusted content as safe:\n  - Avoid `Markup(...)` on user data.\n  - Avoid Jinja `|safe` on user-controlled content.\n- MUST quote HTML attributes containing Jinja expressions (`value=\"{{ x }}\"` not `value={{ x }}`).\n- MUST NOT serve uploaded HTML as active HTML; serve as download (`Content-Disposition: attachment`) or transform to a safe format. Note: This is only relevant if it is possible to upload document content such as html, js, css, etc. If it purely is image files, there is no concern.\n- SHOULD deploy a Content Security Policy (CSP) to mitigate XSS classes (including `javascript:` in `href`).\n\nInsecure patterns:\n- `Markup(request.args.get(...))`\n- Template filters: `{{ user_html|safe }}`\n- Unquoted attributes in templates\n- Serving user-uploaded content directly with `text/html` or inline rendering\n\nDetection hints:\n- Search for `Markup(` and investigate origin of the data.\n- Search template files for `|safe`, `|tojson` misuse, and unquoted attributes.\n- Review file-serving routes that might return user uploads without `as_attachment=True`. Note: This is only relevant if it is possible to upload document content such as html, js, css, etc. If it purely is image files, there is no concern.\n\nFix:\n- Remove unsafe marking; sanitize only when strictly necessary using a trusted HTML sanitizer.\n- Always quote attributes.\n- Add CSP and reduce inline scripts.\n\n---\n\n### FLASK-SSTI-001: Never render untrusted templates (Server-Side Template Injection)\nSeverity: Critical\n\nRequired:\n- MUST NOT render templates that contain user-controlled template syntax.\n- MUST treat `render_template_string` and `Environment.from_string(...).render(...)` as dangerous if the template string is influenced by untrusted input.\n- MUST NOT use use `.format()` on user controlled strings\n- If untrusted templates are absolutely required, treat it as a special high-risk design:\n  - MUST use a sandboxed templating approach and restrict capabilities.\n  - MUST keep Jinja updated and assume sandbox escapes are possible; isolate further.\n\nInsecure patterns:\n- `render_template_string(request.args[\"tmpl\"], ...)`\n- Storing user templates in DB and rendering them with the normal Jinja environment.\n- `request.args[\"tmpl\"].format(...)`\n\nDetection hints:\n- Grep for `render_template_string`, `from_string`, `.render(` with dynamic strings.\n- Trace the origin of the template string (DB, request, uploads, admin panels).\n\nFix:\n- Replace with safe templating alternatives that do not evaluate code (e.g., string.Template, str.replace).\n- If templates must be user-defined, use a sandbox plus strict allowlists and heavy isolation.\n\n---\n\n### FLASK-HEADERS-001: Set essential security headers (in app or at the edge)\nSeverity: Medium\n\nRequired (typical web app):\n- SHOULD set:\n  - CSP (`Content-Security-Policy`)\n  - `X-Content-Type-Options: nosniff`\n  - Clickjacking protection (`X-Frame-Options: SAMEORIGIN` and/or CSP `frame-ancestors`) (there may be cases where the user wants to iframe their site elsewhere. If that is the case, work with them to safely allow it)\n- SHOULD consider additional hardening headers depending on app (Referrer-Policy, Permissions-Policy).\n- MUST ensure cookies are set with secure attributes (see FLASK-SESS-001).\n\nNOTE: Security headers may be set via a proxy or other cloud provider. Check to see if there is evidence of that.\n\nInsecure patterns:\n- No security headers anywhere (app or edge).\n- CSP missing on apps that display untrusted content.\n\nDetection hints:\n- Search for `after_request` hooks, Flask-Talisman usage, reverse proxy config.\n- If not visible in app code, flag as “verify at edge”.\n\nFix:\n- Set headers centrally (middleware / after_request) or via reverse proxy/CDN.\n- Keep CSP realistic and compatible; avoid `unsafe-inline` where possible.\n\n---\n\n### FLASK-LIMITS-001: Request size and form parsing limits MUST be set appropriately\nSeverity: Low (Medium if file uploads / large bodies are possible)\n\nRequired:\n- SHOULD set and justify:\n  - `MAX_CONTENT_LENGTH` (global maximum request bytes)\n  - `MAX_FORM_MEMORY_SIZE` (max per non-file form field in multipart)\n  - `MAX_FORM_PARTS` (max number of multipart fields)\n- MUST enforce additional limits at the reverse proxy / WSGI / platform level where possible.\n\nInsecure patterns:\n- Unlimited request body sizes when handling uploads or user content.\n- Accepting arbitrarily large multipart forms or many fields.\n\nDetection hints:\n- Inspect Flask config for these keys.\n- Inspect upload routes and APIs that accept large JSON.\n\nFix:\n- Set conservative defaults, override per-route only when needed.\n- Ensure large uploads use dedicated upload mechanisms.\n\n---\n\n### FLASK-HOST-001: Host header must be validated in production\nSeverity: Low (depends on app’s use of external URLs)\n\nRequired:\n- MUST set `TRUSTED_HOSTS` in production to restrict accepted Host values.\n- MUST NOT rely on `SERVER_NAME` as a host restriction mechanism.\n\nInsecure patterns:\n- `TRUSTED_HOSTS` unset in production.\n- Code that generates external URLs for emails/password resets without host validation.\n\nDetection hints:\n- Find `TRUSTED_HOSTS` config usage.\n- Find `url_for(..., _external=True)` and check how host is determined.\n\nFix:\n- Set `TRUSTED_HOSTS` to your expected domains (and required subdomains).\n- Ensure external URL generation uses trusted host/scheme.\n\n---\n\n### FLASK-PROXY-001: Reverse proxy trust must be configured correctly\nSeverity: Medium (High if relying on IPs for auth)\n\nRequired:\n- If behind a reverse proxy, MUST configure Flask/Werkzeug to trust forwarded headers only from the intended proxy.\n- MUST NOT blindly trust `X-Forwarded-*` headers from the open internet.\n\nInsecure patterns:\n- `ProxyFix` applied with overly broad trust settings, or applied without understanding how many proxies are in front.\n- Relying on forwarded headers for scheme/host without validation.\n\nDetection hints:\n- Search for `ProxyFix`.\n- Search for usage of `request.remote_addr`, `request.scheme`, `request.host` in security-sensitive logic.\n\nFix:\n- Configure `ProxyFix` (or platform-specific settings) with correct hop counts.\n- Keep `TRUSTED_HOSTS` in place even behind proxies.\n\n---\n\n### FLASK-PATH-001: Prevent path traversal and unsafe file serving\nSeverity: High\n\nRequired:\n- MUST NOT pass user-controlled file paths to `send_file` or to direct file I/O.\n- MUST use safe file serving patterns:\n  - `send_from_directory` for user-specified paths under a trusted base directory\n  - `safe_join` for joining a trusted base directory with untrusted path components\n  - `secure_filename` for uploaded filenames (and still generate your own unique storage name)\n- MUST ensure user uploads are not served as executable/active content (especially HTML).\n- SHOULD in general use `safe_join` over `os.path.join` for almost any filesystem path computations.\n\nInsecure patterns:\n- `send_file(request.args[\"path\"])`\n- `open(os.path.join(base_dir, user_path))` where `user_path` is untrusted\n- Serving uploads from within a static web root without restrictions\n\nDetection hints:\n- Search for `send_file(`, `open(`, `os.path.join(`, `pathlib.Path(...)/...` in file routes.\n- Identify where filenames come from (request args, DB, headers).\n\nFix:\n- Serve only from a non-user-controlled directory base.\n- Store uploads outside static roots; serve through controlled routes.\n- Always validate and normalize file identifiers.\n\nNote: `safe_join` is imported from `werkzeug.security`\n\n---\n\n### FLASK-UPLOAD-001: File uploads must be validated, stored safely, and served safely\nSeverity: High\n\nRequired:\n- MUST enforce upload size limits (app + edge).\n- MUST validate file type using allowlists and content checks (not only extension).\n- MUST store uploads outside executable/static roots when possible.\n- SHOULD generate server-side filenames (random IDs) and avoid trusting original names.\n- MUST serve potentially active formats safely (download attachment) unless explicitly intended.\n\nInsecure patterns:\n- Accepting arbitrary file types and serving them back inline.\n- Using user-supplied filename as storage path.\n- Missing size/type validation.\n\nDetection hints:\n- Look for `request.files[...]` handlers.\n- Check for `secure_filename` usage (and whether it’s combined with uniqueness).\n- Check where files are stored and how they are served.\n\nFix:\n- Implement allowlist validation + safe storage + safe serving.\n- Add scanning / quarantine if applicable.\n\n---\n\n### FLASK-INJECT-001: Prevent SQL injection (use parameterized queries / ORM)\nSeverity: High\n\nRequired:\n- MUST use parameterized queries or an ORM that parameterizes under the hood.\n- MUST NOT build SQL by string concatenation / f-strings with untrusted input.\n\nInsecure patterns:\n- `f\"SELECT ... WHERE id={request.args['id']}\"`\n- `\"... WHERE name = '%s'\" % user_input`\n\nDetection hints:\n- Grep for `SELECT`, `INSERT`, `UPDATE`, `DELETE` strings in Python code.\n- Track untrusted data into DB execute calls.\n\nFix:\n- Replace with parameterized queries or ORM query APIs.\n- Validate types (e.g., int IDs) before querying.\n\n---\n\n### FLASK-INJECT-002: Prevent OS command injection\nSeverity: Critical to High (depends on exposure)\n\nRequired:\n- MUST avoid executing shell commands with untrusted input.\n- If subprocess is necessary:\n  - MUST pass args as a list (not a string)\n  - MUST NOT use `shell=True` with attacker-influenced strings\n  - SHOULD use strict allowlists for any variable component\n- If possible, use pure python or a python library rather than using a subprocess or system command\n- Do not assume that arguments to commands will be inherently safe even in `shell=False`. Commands may incorrectly process these arguments as command line flags or other trusted values.\n\nInsecure patterns:\n- `os.system(user_input)`\n- `subprocess.run(f\"cmd {user}\", shell=True)`\n- Passing user strings into `bash -c`, `sh -c`, PowerShell, etc.\n\nDetection hints:\n- Search for `os.system`, `subprocess`, `Popen`, `shell=True`.\n- Trace data from request/DB into these calls.\n\nFix:\n- Use library APIs instead of shell commands.\n- If unavoidable, hard-code the command and allowlist validated parameters. If supported by the subcommand, try to keep user values after `--` to prevent them being processed as command line flags.\n\n---\n\n### FLASK-SSRF-001: Prevent server-side request forgery (SSRF) in outbound HTTP\nSeverity: Medium\n\n- Note: For small stand alone projects this is less important. It is most important when deploying into an LAN or with other services listening on the same server.\n\nRequired:\n- MUST treat outbound requests to user-provided URLs as high risk.\n- SHOULD validate and restrict destinations (allowlist hosts/domains) for any user-influenced URL fetch.\n- SHOULD block access to:\n  - localhost / private IP ranges / link-local addresses\n  - cloud metadata endpoints\n- MUST NOT allow non http/https protocols (ie file: etc)\n- SHOULD set timeouts and restrict redirects.\n\n\n\nInsecure patterns:\n- `requests.get(request.args[\"url\"])`\n- Webhooks/preview/fetch endpoints that accept arbitrary URLs.\n\nDetection hints:\n- Search for `requests.get/post`, `httpx`, `urllib`, `aiohttp` usage with untrusted URL sources.\n- Identify URL fetch features (preview, import, webhook tester).\n\nFix:\n- Ensure URLs are http or https (disallow file: or other protocols)\n- Enforce allowlists and network egress controls.\n- Add strict parsing and IP resolution checks; set timeouts; disable redirects if not needed.\n\n---\n\n### FLASK-REDIRECT-001: Prevent open redirects\nSeverity: Low\n\nRequired:\n- MUST validate redirect targets derived from untrusted input (e.g., `next`, `redirect`, `return_to`).\n- SHOULD use allowlists of internal paths or known domains.\n- SHOULD prefer redirecting only to same-site relative paths.\n\nInsecure patterns:\n- `redirect(request.args.get(\"next\"))` with no validation.\n\nDetection hints:\n- Search for `redirect(` and examine where `location` comes from.\n\nFix:\n- Only allow relative paths or allowlisted domains.\n- Fall back to a safe default if validation fails.\n\n---\n\n### FLASK-HTTP-001: Use HTTP methods safely; do not change state via GET; avoid secrets in URLs\nSeverity: Medium\n\nRequired:\n- MUST NOT perform state-changing actions over GET.\n- MUST NOT put secrets in URLs (query strings are commonly logged and leaked via referrers).\n- SHOULD require POST/PUT/PATCH/DELETE for state change and apply CSRF protections when cookie-authenticated.\n\nInsecure patterns:\n- `/delete?id=...` implemented as GET\n- Password reset tokens or API keys in query params\n\nDetection hints:\n- Enumerate GET routes and inspect whether they mutate state.\n- Look for URL parameters named `token`, `key`, `secret`, `password`, etc.\n\nFix:\n- Move state changes to non-GET methods.\n- Move sensitive values to secure channels (POST bodies, headers) and protect them.\n\n---\n\n### FLASK-CORS-001: CORS must be explicit and least-privilege\nSeverity: Medium (High if misconfigured with credentials)\n\nRequired:\n- If CORS is not needed, MUST keep it disabled.\n- If CORS is needed:\n  - MUST allowlist trusted origins (do not reflect arbitrary origins).\n  - MUST be careful with credentialed requests; do not combine broad origins with cookies.\n  - SHOULD restrict allowed methods and headers.\n\nInsecure patterns:\n- `Access-Control-Allow-Origin: *` paired with credentialed cookies or overly broad access.\n- Reflecting `Origin` without validation.\n- `flask_cors.CORS(app)` with permissive defaults.\n\nDetection hints:\n- Search for `flask_cors`, `CORS(`, `Access-Control-Allow-Origin`.\n- Check for `supports_credentials=True` and wildcard origins.\n\nFix:\n- Use a strict origin allowlist and minimal methods/headers.\n- Ensure cookie-authenticated endpoints are not exposed cross-origin unless necessary.\n\n---\n\n### FLASK-SUPPLY-001: Dependency and patch hygiene (focus on security-relevant deps)\nSeverity: Low\n\nRequired:\n- SHOULD pin and regularly update security-critical dependencies (Flask, Werkzeug, Jinja2, itsdangerous).\n- MUST respond to known security advisories promptly.\n\nAudit focus example:\n- If running on Windows and using file serving with untrusted paths, ensure Werkzeug’s `safe_join` behavior is not vulnerable to Windows device-name edge cases.\n\nDetection hints:\n- Check `requirements.txt`, lockfiles, and runtime environments.\n- Identify where security helpers are used (safe_join, send_from_directory).\n\nFix:\n- Upgrade to patched versions and add regression tests for the impacted behavior.\n\n--------------------------------------------------------------------\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n- Dev server / debug:\n  - `app.run(`, `flask run`, `--debug`, `DEBUG=True`, `FLASK_DEBUG`\n- Secrets:\n  - `SECRET_KEY`, `secret_key`, `.env` committed, `print(config)`\n- Cookies / sessions:\n  - `SESSION_COOKIE_SECURE`, `SESSION_COOKIE_HTTPONLY`, `SESSION_COOKIE_SAMESITE`\n  - `session[...] =` with sensitive values\n- CSRF:\n  - POST/PUT/PATCH/DELETE handlers without CSRF checks in cookie-authenticated apps\n- XSS/SSTI:\n  - `Markup(`, `|safe`, unquoted attributes, `render_template_string`\n- Files:\n  - `send_file(` with user-controlled path; `open(` on user path; `os.path.join` with untrusted\n  - upload handlers using user filename for path\n- Injection:\n  - SQL strings + string formatting into `.execute(...)`\n  - `subprocess.*`, `shell=True`, `os.system`\n- SSRF:\n  - `requests.get/post` or `httpx` with URL from request/DB\n- Redirect:\n  - `redirect(request.args.get(\"next\"))`\n- CORS:\n  - `flask_cors.CORS` permissive configs; wildcard origins with credentials\n\nAlways try to confirm:\n- data origin (untrusted vs trusted)\n- sink type (template/SQL/subprocess/files/redirect/http)\n- protective controls present (validation, allowlists, middleware)\n\n--------------------------------------------------------------------\n\n## 6) Sources (accessed 2026-01-26)\n\nPrimary framework documentation:\n- Flask Docs: Deploying to Production — https://flask.palletsprojects.com/en/stable/deploying/\n- Flask Docs: Debugging Application Errors — https://flask.palletsprojects.com/en/stable/debugging/\n- Flask Docs: Configuration Handling — https://flask.palletsprojects.com/en/stable/config/\n- Flask Docs: Security Considerations — https://flask.palletsprojects.com/en/stable/web-security/\n- Flask Docs: Tell Flask it is Behind a Proxy — https://flask.palletsprojects.com/en/stable/deploying/proxy_fix/\n- Flask API Docs: Sessions — https://flask.palletsprojects.com/en/stable/api/#sessions\n\nWerkzeug documentation & advisories:\n- Werkzeug Docs: Utilities (send_file / send_from_directory / safe_join / secure_filename / password hashing) — https://werkzeug.palletsprojects.com/en/stable/utils/\n- GitHub Advisory: CVE-2025-66221 (Werkzeug safe_join Windows device names) — https://github.com/advisories/GHSA-hgf8-39gv-g3f2\n\nOWASP Cheat Sheet Series:\n- Session Management — https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html\n- CSRF Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html\n- XSS Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html\n- Input Validation — https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html\n- SQL Injection Prevention — https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html\n- Injection Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Injection_Prevention_Cheat_Sheet.html\n- OS Command Injection Defense — https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html\n- SSRF Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html\n- File Upload — https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html\n- Unvalidated Redirects — https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html\n- HTTP Headers — https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html\n\nTemplate safety references:\n- Jinja: Sandbox (rendering untrusted templates) — https://jinja.palletsprojects.com/en/stable/sandbox/\n- OWASP WSTG: Testing for Server-Side Template Injection — https://owasp.org/www-project-web-security-testing-guide/v41/4-Web_Application_Security_Testing/07-Input_Validation_Testing/18-Testing_for_Server_Side_Template_Injection\n- PortSwigger Web Security Academy: Server-side template injection — https://portswigger.net/web-security/server-side-template-injection\n\nHTTP semantics:\n- RFC 9110: HTTP Semantics (safe methods) — https://www.rfc-editor.org/rfc/rfc9110\n","core/skills/builtin/security-ownership-map/SKILL.md":"---\nname: \"security-ownership-map\"\ndescription: \"Analyze git repositories to build a security ownership topology (people-to-file), compute bus factor and sensitive-code ownership, and export CSV/JSON for graph databases and visualization. Trigger only when the user explicitly wants a security-oriented ownership or bus-factor analysis grounded in git history (for example: orphaned sensitive code, security maintainers, CODEOWNERS reality checks for risk, sensitive hotspots, or ownership clusters). Do not trigger for general maintainer lists or non-security ownership questions.\"\n---\n\n# Security Ownership Map\n\n## Overview\n\nBuild a bipartite graph of people and files from git history, then compute ownership risk and export graph artifacts for Neo4j/Gephi. Also build a file co-change graph (Jaccard similarity on shared commits) to cluster files by how they move together while ignoring large, noisy commits.\n\n## Requirements\n\n- Python 3\n- `networkx` (required; community detection is enabled by default)\n\nInstall with:\n\n```bash\npip install networkx\n```\n\n## Workflow\n\n1. Scope the repo and time window (optional `--since/--until`).\n2. Decide sensitivity rules (use defaults or provide a CSV config).\n3. Build the ownership map with `scripts/run_ownership_map.py` (co-change graph is on by default; use `--cochange-max-files` to ignore supernode commits).\n4. Communities are computed by default; graphml output is optional (`--graphml`).\n5. Query the outputs with `scripts/query_ownership.py` for bounded JSON slices.\n6. Persist and visualize (see `references/neo4j-import.md`).\n\nBy default, the co-change graph ignores common “glue” files (lockfiles, `.github/*`, editor config) so clusters reflect actual code movement instead of shared infra edits. Override with `--cochange-exclude` or `--no-default-cochange-excludes`. Dependabot commits are excluded by default; override with `--no-default-author-excludes` or add patterns via `--author-exclude-regex`.\n\nIf you want to exclude Linux build glue like `Kbuild` from co-change clustering, pass:\n\n```bash\npython skills/skills/security-ownership-map/scripts/run_ownership_map.py \\\n  --repo /path/to/linux \\\n  --out ownership-map-out \\\n  --cochange-exclude \"**/Kbuild\"\n```\n\n## Quick start\n\nRun from the repo root:\n\n```bash\npython skills/skills/security-ownership-map/scripts/run_ownership_map.py \\\n  --repo . \\\n  --out ownership-map-out \\\n  --since \"12 months ago\" \\\n  --emit-commits\n```\n\nDefaults: author identity, author date, and merge commits excluded. Use `--identity committer`, `--date-field committer`, or `--include-merges` if needed.\n\nExample (override co-change excludes):\n\n```bash\npython skills/skills/security-ownership-map/scripts/run_ownership_map.py \\\n  --repo . \\\n  --out ownership-map-out \\\n  --cochange-exclude \"**/Cargo.lock\" \\\n  --cochange-exclude \"**/.github/**\" \\\n  --no-default-cochange-excludes\n```\n\nCommunities are computed by default. To disable:\n\n```bash\npython skills/skills/security-ownership-map/scripts/run_ownership_map.py \\\n  --repo . \\\n  --out ownership-map-out \\\n  --no-communities\n```\n\n## Sensitivity rules\n\nBy default, the script flags common auth/crypto/secret paths. Override by providing a CSV file:\n\n```\n# pattern,tag,weight\n**/auth/**,auth,1.0\n**/crypto/**,crypto,1.0\n**/*.pem,secrets,1.0\n```\n\nUse it with `--sensitive-config path/to/sensitive.csv`.\n\n## Output artifacts\n\n`ownership-map-out/` contains:\n\n- `people.csv` (nodes: people)\n- `files.csv` (nodes: files)\n- `edges.csv` (edges: touches)\n- `cochange_edges.csv` (file-to-file co-change edges with Jaccard weight; omitted with `--no-cochange`)\n- `summary.json` (security ownership findings)\n- `commits.jsonl` (optional, if `--emit-commits`)\n- `communities.json` (computed by default from co-change edges when available; includes `maintainers` per community; disable with `--no-communities`)\n- `cochange.graph.json` (NetworkX node-link JSON with `community_id` + `community_maintainers`; falls back to `ownership.graph.json` if no co-change edges)\n- `ownership.graphml` / `cochange.graphml` (optional, if `--graphml`)\n\n`people.csv` includes timezone detection based on author commit offsets: `primary_tz_offset`, `primary_tz_minutes`, and `timezone_offsets`.\n\n## LLM query helper\n\nUse `scripts/query_ownership.py` to return small, JSON-bounded slices without loading the full graph into context.\n\nExamples:\n\n```bash\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out people --limit 10\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out files --tag auth --bus-factor-max 1\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out person --person alice@corp --limit 10\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out file --file crypto/tls\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out cochange --file crypto/tls --limit 10\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out summary --section orphaned_sensitive_code\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out community --id 3\n```\n\nUse `--community-top-owners 5` (default) to control how many maintainers are stored per community.\n\n## Basic security queries\n\nRun these to answer common security ownership questions with bounded output:\n\n```bash\n# Orphaned sensitive code (stale + low bus factor)\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out summary --section orphaned_sensitive_code\n\n# Hidden owners for sensitive tags\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out summary --section hidden_owners\n\n# Sensitive hotspots with low bus factor\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out summary --section bus_factor_hotspots\n\n# Auth/crypto files with bus factor <= 1\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out files --tag auth --bus-factor-max 1\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out files --tag crypto --bus-factor-max 1\n\n# Who is touching sensitive code the most\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out people --sort sensitive_touches --limit 10\n\n# Co-change neighbors (cluster hints for ownership drift)\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out cochange --file path/to/file --min-jaccard 0.05 --limit 20\n\n# Community maintainers (for a cluster)\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out community --id 3\n\n# Monthly maintainers for the community containing a file\npython skills/skills/security-ownership-map/scripts/community_maintainers.py \\\n  --data-dir ownership-map-out \\\n  --file network/card.c \\\n  --since 2025-01-01 \\\n  --top 5\n\n# Quarterly buckets instead of monthly\npython skills/skills/security-ownership-map/scripts/community_maintainers.py \\\n  --data-dir ownership-map-out \\\n  --file network/card.c \\\n  --since 2025-01-01 \\\n  --bucket quarter \\\n  --top 5\n```\n\nNotes:\n- Touches default to one authored commit (not per-file). Use `--touch-mode file` to count per-file touches.\n- Use `--window-days 90` or `--weight recency --half-life-days 180` to smooth churn.\n- Filter bots with `--ignore-author-regex '(bot|dependabot)'`.\n- Use `--min-share 0.1` to show stable maintainers only.\n- Use `--bucket quarter` for calendar quarter groupings.\n- Use `--identity committer` or `--date-field committer` to switch from author attribution.\n- Use `--include-merges` to include merge commits (excluded by default).\n\n### Summary format (default)\n\nUse this structure, add fields if needed:\n\n```json\n{\n  \"orphaned_sensitive_code\": [\n    {\n      \"path\": \"crypto/tls/handshake.rs\",\n      \"last_security_touch\": \"2023-03-12T18:10:04+00:00\",\n      \"bus_factor\": 1\n    }\n  ],\n  \"hidden_owners\": [\n    {\n      \"person\": \"alice@corp\",\n      \"controls\": \"63% of auth code\"\n    }\n  ]\n}\n```\n\n## Graph persistence\n\nUse `references/neo4j-import.md` when you need to load the CSVs into Neo4j. It includes constraints, import Cypher, and visualization tips.\n\n## Notes\n\n- `bus_factor_hotspots` in `summary.json` lists sensitive files with low bus factor; `orphaned_sensitive_code` is the stale subset.\n- If `git log` is too large, narrow with `--since` or `--until`.\n- Compare `summary.json` against CODEOWNERS to highlight ownership drift.\n","core/skills/builtin/security-ownership-map/agents/openai.yaml":"interface:\n  display_name: \"Security Ownership Map\"\n  short_description: \"Map maintainers, bus factor, and sensitive code ownership\"\n  default_prompt: \"Build a security ownership map for this repository and identify bus-factor risks in sensitive code.\"\n","core/skills/builtin/security-ownership-map/references/neo4j-import.md":"# Neo4j Import Notes\n\nUse these steps when persisting the ownership graph to Neo4j.\n\n## Quick import (LOAD CSV)\n\n1. Copy `people.csv`, `files.csv`, and `edges.csv` into the Neo4j import directory.\n2. Run the following Cypher from Neo4j Browser or `cypher-shell`:\n\n```cypher\nCREATE CONSTRAINT person_id IF NOT EXISTS FOR (p:Person) REQUIRE p.id IS UNIQUE;\nCREATE CONSTRAINT file_id IF NOT EXISTS FOR (f:File) REQUIRE f.id IS UNIQUE;\n\nLOAD CSV WITH HEADERS FROM 'file:///people.csv' AS row\nMERGE (p:Person {id: row.person_id})\nSET p.name = row.name,\n    p.email = row.email,\n    p.first_seen = row.first_seen,\n    p.last_seen = row.last_seen,\n    p.commit_count = toInteger(row.commit_count),\n    p.touches = toInteger(row.touches),\n    p.sensitive_touches = toFloat(row.sensitive_touches),\n    p.primary_tz_offset = CASE row.primary_tz_offset WHEN '' THEN null ELSE row.primary_tz_offset END,\n    p.primary_tz_minutes = CASE row.primary_tz_minutes WHEN '' THEN null ELSE toInteger(row.primary_tz_minutes) END,\n    p.timezone_offsets = CASE row.timezone_offsets WHEN '' THEN null ELSE row.timezone_offsets END;\n\nLOAD CSV WITH HEADERS FROM 'file:///files.csv' AS row\nMERGE (f:File {id: row.file_id})\nSET f.path = row.path,\n    f.first_seen = row.first_seen,\n    f.last_seen = row.last_seen,\n    f.commit_count = toInteger(row.commit_count),\n    f.touches = toInteger(row.touches),\n    f.bus_factor = toInteger(row.bus_factor),\n    f.sensitivity_score = toFloat(row.sensitivity_score),\n    f.sensitivity_tags = row.sensitivity_tags;\n\nLOAD CSV WITH HEADERS FROM 'file:///edges.csv' AS row\nMATCH (p:Person {id: row.person_id})\nMATCH (f:File {id: row.file_id})\nMERGE (p)-[r:TOUCHES]->(f)\nSET r.touches = toInteger(row.touches),\n    r.recency_weight = toFloat(row.recency_weight),\n    r.first_seen = row.first_seen,\n    r.last_seen = row.last_seen,\n    r.sensitive_weight = toFloat(row.sensitive_weight);\n\nLOAD CSV WITH HEADERS FROM 'file:///cochange_edges.csv' AS row\nMATCH (f1:File {id: row.file_a})\nMATCH (f2:File {id: row.file_b})\nMERGE (f1)-[r:COCHANGES]->(f2)\nSET r.cochange_count = toInteger(row.cochange_count),\n    r.jaccard = toFloat(row.jaccard);\n```\n\n## Visualization tips\n\n- Use Neo4j Bloom or Browser with `MATCH (p:Person)-[r:TOUCHES]->(f:File) RETURN p,r,f`.\n- Filter by `f.sensitivity_score > 0` to highlight security-relevant clusters.\n- For Gephi, import `edges.csv` as edges and `files.csv` / `people.csv` as nodes.\n","core/skills/builtin/security-threat-model/SKILL.md":"---\nname: \"security-threat-model\"\ndescription: \"Repository-grounded threat modeling that enumerates trust boundaries, assets, attacker capabilities, abuse paths, and mitigations, and writes a concise Markdown threat model. Trigger only when the user explicitly asks to threat model a codebase or path, enumerate threats/abuse paths, or perform AppSec threat modeling. Do not trigger for general architecture summaries, code review, or non-security design work.\"\n---\n\n# Threat Model Source Code Repo\n\nDeliver an actionable AppSec-grade threat model that is specific to the repository or a project path, not a generic checklist. Anchor every architectural claim to evidence in the repo and keep assumptions explicit. Prioritizing realistic attacker goals and concrete impacts over generic checklists.\n\n## Quick start\n\n1) Collect (or infer) inputs:\n- Repo root path and any in-scope paths.\n- Intended usage, deployment model, internet exposure, and auth expectations (if known).\n- Any existing repository summary or architecture spec.\n- Use prompts in `references/prompt-template.md` to generate a repository summary.\n- Follow the required output contract in `references/prompt-template.md`. Use it verbatim when possible.\n\n## Workflow\n\n### 1) Scope and extract the system model\n- Identify primary components, data stores, and external integrations from the repo summary.\n- Identify how the system runs (server, CLI, library, worker) and its entrypoints.\n- Separate runtime behavior from CI/build/dev tooling and from tests/examples.\n- Map the in-scope locations to those components and exclude out-of-scope items explicitly.\n- Do not claim components, flows, or controls without evidence.\n\n### 2) Derive boundaries, assets, and entry points\n- Enumerate trust boundaries as concrete edges between components, noting protocol, auth, encryption, validation, and rate limiting.\n- List assets that drive risk (data, credentials, models, config, compute resources, audit logs).\n- Identify entry points (endpoints, upload surfaces, parsers/decoders, job triggers, admin tooling, logging/error sinks).\n\n### 3) Calibrate assets and attacker capabilities\n- List the assets that drive risk (credentials, PII, integrity-critical state, availability-critical components, build artifacts).\n- Describe realistic attacker capabilities based on exposure and intended usage.\n- Explicitly note non-capabilities to avoid inflated severity.\n\n\n### 4) Enumerate threats as abuse paths\n- Prefer attacker goals that map to assets and boundaries (exfiltration, privilege escalation, integrity compromise, denial of service).\n- Classify each threat and tie it to impacted assets.\n- Keep the number of threats small but high quality.\n\n### 5) Prioritize with explicit likelihood and impact reasoning\n- Use qualitative likelihood and impact (low/medium/high) with short justifications.\n- Set overall priority (critical/high/medium/low) using likelihood x impact, adjusted for existing controls.\n- State which assumptions most influence the ranking.\n\n### 6) Validate service context and assumptions with the user\n- Summarize key assumptions that materially affect threat ranking or scope, then ask the user to confirm or correct them.\n- Ask 1–3 targeted questions to resolve missing context (service owner and environment, scale/users, deployment model, authn/authz, internet exposure, data sensitivity, multi-tenancy).\n- Pause and wait for user feedback before producing the final report.\n- If the user declines or can’t answer, state which assumptions remain and how they influence priority.\n\n### 7) Recommend mitigations and focus paths\n- Distinguish existing mitigations (with evidence) from recommended mitigations.\n- Tie mitigations to concrete locations (component, boundary, or entry point) and control types (authZ checks, input validation, schema enforcement, sandboxing, rate limits, secrets isolation, audit logging).\n- Prefer specific implementation hints over generic advice (e.g., \"enforce schema at gateway for upload payloads\" vs \"validate inputs\").\n- Base recommendations on validated user context; if assumptions remain unresolved, mark recommendations as conditional.\n\n### 8) Run a quality check before finalizing\n- Confirm all discovered entrypoints are covered.\n- Confirm each trust boundary is represented in threats.\n- Confirm runtime vs CI/dev separation.\n- Confirm user clarifications (or explicit non-responses) are reflected.\n- Confirm assumptions and open questions are explicit.\n- Confirm that the format of the report matches closely the required output format defined in prompt template: `references/prompt-template.md`\n- Write the final Markdown to a file named `<repo-or-dir-name>-threat-model.md` (use the basename of the repo root, or the in-scope directory if you were asked to model a subpath).\n\n\n## Risk prioritization guidance (illustrative, not exhaustive)\n- High: pre-auth RCE, auth bypass, cross-tenant access, sensitive data exfiltration, key or token theft, model or config integrity compromise, sandbox escape.\n- Medium: targeted DoS of critical components, partial data exposure, rate-limit bypass with measurable impact, log/metrics poisoning that affects detection.\n- Low: low-sensitivity info leaks, noisy DoS with easy mitigation, issues requiring unlikely preconditions.\n\n## References\n\n- Output contract and full prompt template: `references/prompt-template.md`\n- Optional controls/asset list: `references/security-controls-and-assets.md`\n\nOnly load the reference files you need. Keep the final result concise, grounded, and reviewable.\n","core/skills/builtin/security-threat-model/agents/openai.yaml":"interface:\n  display_name: \"Security Threat Model\"\n  short_description: \"Repo-grounded threat modeling and abuse-path analysis\"\n  default_prompt: \"Create a repository-grounded threat model for this codebase with prioritized abuse paths and mitigations.\"\n","core/skills/builtin/security-threat-model/references/prompt-template.md":"# Threat Modeling Prompt Template for LLMs\n\nThis reference provides a disciplined, repo-grounded prompt that produces AppSec-usable threat models. Use it when you need a reliable output contract and a consistent process to assemble the threat model output\n\n## System prompt\n\nUse this as a stable system prompt:\n\n````text\nYou are a senior application security engineer producing a threat model that will be read by other AppSec engineers.\n\nPrimary objective:\n- Generate a threat model that is specific to THIS repository and its real-world usage.\n- Prefer concrete, evidence-backed findings over generic vulnerability checklists.\n\nEvidence and grounding rules:\n- Do not invent components, data stores, endpoints, flows, or controls.\n- Every architectural claim must be backed by at least one \"Evidence anchor\" referencing a repo path\n  (and a symbol name, config key, or a short quoted snippet if available).\n- If information is missing, state assumptions explicitly and list the open questions needed to validate them.\n\nSecurity hygiene:\n- Never output secrets. If you encounter tokens/keys/passwords, redact them and only describe their presence and location.\n\nThreat modeling approach:\n- Model the system using data flows and trust boundaries.\n- Enumerate threats and produce attack goals and abuse paths\n- Prioritize threats using explicit likelihood and impact reasoning (qualitative is acceptable: low/medium/high).\n\nScope discipline:\n- Clearly separate: production/runtime behavior vs CI/build/dev tooling vs tests/examples.\n- Clearly separate attacker-controlled inputs vs operator-controlled inputs vs developer-controlled inputs.\n- If a vulnerability class requires attacker control that likely does not exist for this repo's real usage, say so and downgrade severity.\n\nCommunication quality:\n- Write for AppSec engineers: concise but specific.\n- Use precise terminology. Include mitigations and residual risks.\n- Avoid restating large blocks of README/spec; summarize and point to evidence.\n\nDiagram requirements:\n- Produce a single compact Mermaid flowchart showing primary components and trust boundaries.\n- Mermaid must render cleanly. Use a conservative subset:\n  - Use `flowchart TD` or `flowchart LR` and only `-->` arrows.\n  - Use simple node IDs (letters/numbers/underscores only) and quoted labels (e.g., `A[\"Label\"]`); avoid `A(Label)` shape syntax.\n  - Do not use Mermaid `title` lines or `style` directives.\n  - Keep edge labels to plain words/spaces only via `-->|label|`; avoid `{}`, `[]`, `()`, or quotes in edge labels (if needed, drop the label).\n  - Keep node labels short and readable: do not include file paths, URLs, or socket paths (put those details in prose outside the diagram).\n- Wrap the diagram in a Markdown fenced block:\n  ```mermaid\n  <mermaid syntax here>\n  ```\n````\n\n## Repository summary prompt\n\n```\nWe have a codebase located at {repo_directory/path}, currently on branch {branch_name}.\n\nPlease produce a security-oriented summary of the repository (or the specified sub-path) with the goal of helping a follow-on security engineer quickly understand the system well enough to build an initial threat model and investigate potential security hypotheses.\n\nObjectives\n1.\tProject overview\n\t•\tIdentify the primary programming languages, frameworks, and build system.\n\t•\tSummarize the project’s core purpose and high-level architecture.\n\t•\tDescribe major components, services, or modules and how they interact.\n2.\tSecurity posture and entry points\n\t•\tIdentify likely user entry points and trust boundaries.\n\t•\tDescribe existing security layers (e.g., authentication, authorization, validation, sandboxing, isolation, privilege boundaries).\n\t•\tCall out security-critical components and assumptions that must hold for the system to remain secure.\n\nGuidance for Security Analysis\n\nStructure the summary so an application security engineer can quickly answer questions such as:\n\t•\tWhere does user input originate?\n\t•\tHow is untrusted data parsed, validated, and handled?\n\t•\tWhat security assumptions should not be violated?\n\t•\tWhere are the most likely choke points for security bugs?\n\nAdapt the analysis to the project type. For example:\n\t•\tWeb applications: where requests enter, how user data is parsed, routed, authenticated, and stored.\n\t•\tCommand-line tools: supported inputs (arguments, files, environment variables, stdin) and how they are processed.\n\t•\tNetwork daemons: exposed ports, supported protocols, message formats, and request handling paths.\n\t•\tOperating system or low-level components: common vulnerability classes (e.g., memory corruption, logic flaws) that could lead to LPE or RCE.\n\nBe thorough but pragmatic: the goal is to help a security engineer quickly determine whether a discovered bug is security-relevant and where deeper investigation should focus.\n\nTooling Notes\n\nIf Ripgrep (rg) is available, use it to explore the codebase. When using grep or rg, always include the -I flag to avoid searching through binary files.\n```\n\n\n\n## User prompt template\n\nUse this as the task prompt, filling in what you know and marking the rest as assumptions:\n\n```text\n# Inputs\nContext (fill as available; otherwise infer and mark assumptions):\n- intended_usage: {intended_usage}\n- deployment_model: {deployment_model}\n- data_sensitivity: {data_sensitivity}\n- internet_exposure: {internet_exposure}\n- authn_authz_expectations: {authn_authz_expectations}\n- out_of_scope: {out_of_scope}\n\nProvided summaries (may be incomplete):\n- repository_summary: {repository_summary}\n\n\nIn-scope code locations (if known):\n- in_scope_paths: {in_scope_paths}\n\n# Task\nConstruct a repo-centric threat model that helps AppSec engineers understand the most important security risks and where to focus manual review.\n\nYou MUST follow this process and reflect outputs in the final document:\n\n## Process\n1) Repo discovery (evidence collection)\n   a. Identify the repo shape:\n      - languages and frameworks\n      - how it runs (server/cli/library), entrypoints, build artifacts\n   b. Identify security-relevant surfaces and controls by searching for evidences, such as:\n      - network listeners/routes/endpoints; RPC handlers; message consumers\n      - authentication, session/token handling, authorization checks, RBAC/ACL logic\n      - parsing/serialization/deserialization (JSON/YAML/XML/protobuf), template rendering, eval/dynamic code\n      - file upload/read paths, archive extraction, image/document parsing\n      - database/queue/cache clients and query construction\n      - secrets/config loading, environment variables, key management\n      - SSRF-capable HTTP clients, webhooks, URL fetchers\n      - sandboxing/isolation, privilege boundaries, subprocess execution\n      - logging/auditing and error handling paths\n      - CI/build/release: pipelines, dependency management, artifact publishing\n\n2) System model\n   a. Summarize the primary components (runtime plus critical build/CI components when relevant).\n   b. Enumerate data flows and trust boundaries.\n      - For each trust boundary, specify:\n        * source to destination\n        * data types crossing (e.g., credentials, PII, files, tokens, prompts)\n        * channel/protocol (HTTP/gRPC/IPC/file/db)\n        * security guarantees and validation (auth, mTLS, origin checks, schema validation, rate limits)\n   c. Provide a compact Mermaid diagram showing components and trust boundaries.\n\n3) Assets and security objectives\n   - List assets (data, credentials, integrity-critical state, availability-critical components, build artifacts).\n   - For each asset, state why it matters (confidentiality/integrity/availability, compliance, user harm).\n\n4) Attacker model\n   - Capabilities: realistic remote attacker assumptions based on intended usage and exposure.\n   - Non-capabilities: things attacker cannot plausibly do (unless explicitly in scope), to avoid inflated severity.\n\n5) Threat enumeration (concrete, system-specific)\n   - Generate threats as attacker stories tied to:\n     * entry points\n     * trust boundaries\n     * privileged components\n   - Prefer abuse paths (multi-step sequences) over single-line generic threats.\n\n6) Risk prioritization\n   - For each threat:\n     * Likelihood: low/medium/high with a 1 to 2 sentence justification\n     * Impact: low/medium/high with a 1 to 2 sentence justification\n     * Overall priority: critical/high/medium/low (based on likelihood x impact, adjusted for existing controls)\n   - Explicitly state which assumptions most affect risk.\n\n7) Validate assumptions and service context with the user (required before final report)\n   - Summarize key assumptions that materially affect scope or risk ranking.\n   - Ask 1 to 3 targeted questions to resolve missing service meta-context (service owner/environment, scale/users, deployment model, authn/authz, internet exposure, data sensitivity, multi-tenancy).\n   - Pause and wait for user feedback before producing the final report.\n   - If the user cannot answer, proceed with explicit assumptions and mark any conditional conclusions.\n\n8) Mitigations and recommendations\n   - For each high/critical threat:\n     * Existing mitigations (with evidence anchors)\n     * Gaps/weaknesses\n     * Recommended mitigations (code/config/process)\n     * Detection/monitoring ideas (logging, metrics, alerts)\n\n9) Focus paths for manual security review\n   - Output 2 to 30 repo-relative paths (files or directories) that merit deeper review.\n   - For each path, give a one-sentence reason tied to the threat model.\n\n10) Quality check\n   - Provide a short checklist confirming you covered:\n     * all entry points you discovered\n     * each trust boundary at least once in threats\n     * runtime vs CI/dev separation\n     * user clarifications (or explicit non-responses)\n     * assumptions and open questions\n\n## Required output format (exact)\nBefore producing the final Markdown report, first provide an assumption-validation check-in:\n- List the key assumptions in 3 to 6 bullets.\n- Ask 1 to 3 targeted context questions.\n- Wait for the user response, then produce the final report below using the clarified context.\n\nProduce valid Markdown with these sections in this order:\n\n## Executive summary\n- 1 short paragraph on the top risk themes and highest-risk areas.\n\n## Scope and assumptions\n- In-scope paths, out-of-scope items, and explicit assumptions.\n- A short list of open questions that would materially change the risk ranking.\n\n\n## System model\n### Primary components\n### Data flows and trust boundaries\nRepresent the system as a sequence of arrow-style bullets (e.g., Internet → API Server, User Input -> Application Logic, etc). For each boundary, document:\n\t•\tthe primary data types crossing the boundary,\n\t•\tthe communication channel or protocol,\n\t•\tthe security guarantees (e.g., authentication, origin checks, encryption, rate limiting), and\n\t•\tany input validation, normalization, or schema enforcement performed.\n\n#### Diagram\n- Include a single, compact Mermaid diagram (`flowchart TD` or `flowchart LR`) showing primary components and trust boundaries (e.g., separate trust zones via subgraphs). Keep it compact, use only `-->`, avoid `title`/`style`, keep node labels short (no paths/URLs), and keep edge labels to plain words only (avoid `{}`, `[]`, `()`, or quotes).\n\n\n## Assets and security objectives\n- A table: Asset | Why it matters | Security objective (C/I/A)\n\n## Attacker model\n### Capabilities\n### Non-capabilities\n\n## Entry points and attack surfaces\n- A table: Surface | How reached | Trust boundary | Notes | Evidence (repo path / symbol)\n\n## Top abuse paths\n- 5 to 10 short abuse paths, each as a numbered sequence of steps (attacker goal -> steps -> impact).\n\n## Threat model table\n- A Markdown table with columns:\n  Threat ID | Threat source | Prerequisites | Threat action | Impact | Impacted assets | Existing controls (evidence) | Gaps | Recommended mitigations | Detection ideas | Likelihood | Impact severity | Priority\n\nRules:\n- Threat IDs must be stable and formatted: TM-001, TM-002, ...\n- Priority must be one of: critical, high, medium, low.\n- Keep prerequisites to 1 to 2 sentences. Keep recommended mitigations concrete.\n\n## Criticality calibration\n- Define what counts as critical/high/medium/low for THIS repo and context.\n- Include 2 to 3 examples per level (tailored to the repo's assets and exposure).\n\n## Focus paths for security review\n- A table: Path | Why it matters | Related Threat IDs\n\n## Notes on use\n\n- Fill in known context, but allow the model to infer and mark assumptions.\n- Include 1–2 repo-path anchors per major claim; do not dump every match.\n","core/skills/builtin/security-threat-model/references/security-controls-and-assets.md":"# Security Controls and Asset Categories\n\nUse this as a lightweight checklist to keep outputs consistent across teams. Prefer concrete, system-specific items over generic text.\n\n## Asset categories (pick only what applies)\n- User data (PII, content, uploads)\n- Authentication artifacts (passwords, tokens, sessions, cookies)\n- Authorization state (roles, policies, ACLs)\n- Secrets and keys (API keys, signing keys, encryption keys)\n- Configuration and feature flags\n- Models and weights (if ML systems)\n- Source code and build artifacts\n- Audit logs and telemetry\n- Availability-critical resources (queues, caches, rate limits, compute budgets)\n- Tenant isolation boundaries and metadata\n\n## Security control categories\n- Identity and access: authN, authZ, session handling, mTLS, key rotation\n- Input protection: schema validation, parsing hardening, upload scanning, sandboxing\n- Network safeguards: TLS, network policies, WAF, rate limiting, DoS controls\n- Data protection: encryption at rest/in transit, tokenization, redaction\n- Isolation: process sandboxing, container boundaries, tenant isolation, seccomp\n- Observability: audit logs, alerting, anomaly detection, tamper resistance\n- Supply chain: dependency pinning, SBOMs, provenance, signing\n- Change control: CI checks, deployment approvals, config guardrails\n\n## Mitigation phrasing patterns\n- \"Enforce schema at <boundary> for <payload> before <component>.\"\n- \"Require authZ check for <action> on <resource> in <service>.\"\n- \"Isolate <parser/component> in a sandbox with <resource limits>.\"\n- \"Rate limit <endpoint> by <key> and apply burst caps.\"\n- \"Encrypt <data> at rest using <key management> and rotate <keys>.\"\n","core/skills/builtin/skill-creator/SKILL.md":"---\nname: skill-creator\ndescription: Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Codex's capabilities with specialized knowledge, workflows, or tool integrations.\nmetadata:\n  short-description: Create or update a skill\n---\n\n# Skill Creator\n\nThis skill provides guidance for creating effective skills.\n\n## About Skills\n\nSkills are modular, self-contained folders that extend Codex's capabilities by providing\nspecialized knowledge, workflows, and tools. Think of them as \"onboarding guides\" for specific\ndomains or tasks—they transform Codex from a general-purpose agent into a specialized agent\nequipped with procedural knowledge that no model can fully possess.\n\n### What Skills Provide\n\n1. Specialized workflows - Multi-step procedures for specific domains\n2. Tool integrations - Instructions for working with specific file formats or APIs\n3. Domain expertise - Company-specific knowledge, schemas, business logic\n4. Bundled resources - Scripts, references, and assets for complex and repetitive tasks\n\n## Core Principles\n\n### Concise is Key\n\nThe context window is a public good. Skills share the context window with everything else Codex needs: system prompt, conversation history, other Skills' metadata, and the actual user request.\n\n**Default assumption: Codex is already very smart.** Only add context Codex doesn't already have. Challenge each piece of information: \"Does Codex really need this explanation?\" and \"Does this paragraph justify its token cost?\"\n\nPrefer concise examples over verbose explanations.\n\n### Set Appropriate Degrees of Freedom\n\nMatch the level of specificity to the task's fragility and variability:\n\n**High freedom (text-based instructions)**: Use when multiple approaches are valid, decisions depend on context, or heuristics guide the approach.\n\n**Medium freedom (pseudocode or scripts with parameters)**: Use when a preferred pattern exists, some variation is acceptable, or configuration affects behavior.\n\n**Low freedom (specific scripts, few parameters)**: Use when operations are fragile and error-prone, consistency is critical, or a specific sequence must be followed.\n\nThink of Codex as exploring a path: a narrow bridge with cliffs needs specific guardrails (low freedom), while an open field allows many routes (high freedom).\n\n### Anatomy of a Skill\n\nEvery skill consists of a required SKILL.md file and optional bundled resources:\n\n```\nskill-name/\n├── SKILL.md (required)\n│   ├── YAML frontmatter metadata (required)\n│   │   ├── name: (required)\n│   │   └── description: (required)\n│   └── Markdown instructions (required)\n├── agents/ (recommended)\n│   └── openai.yaml - UI metadata for skill lists and chips\n└── Bundled Resources (optional)\n    ├── scripts/          - Executable code (Python/Bash/etc.)\n    ├── references/       - Documentation intended to be loaded into context as needed\n    └── assets/           - Files used in output (templates, icons, fonts, etc.)\n```\n\n#### SKILL.md (required)\n\nEvery SKILL.md consists of:\n\n- **Frontmatter** (YAML): Contains `name` and `description` fields. These are the only fields that Codex reads to determine when the skill gets used, thus it is very important to be clear and comprehensive in describing what the skill is, and when it should be used.\n- **Body** (Markdown): Instructions and guidance for using the skill. Only loaded AFTER the skill triggers (if at all).\n\n#### Agents metadata (recommended)\n\n- UI-facing metadata for skill lists and chips\n- Read references/openai_yaml.md before generating values and follow its descriptions and constraints\n- Create: human-facing `display_name`, `short_description`, and `default_prompt` by reading the skill\n- Generate deterministically by passing the values as `--interface key=value` to `scripts/generate_openai_yaml.py` or `scripts/init_skill.py`\n- On updates: validate `agents/openai.yaml` still matches SKILL.md; regenerate if stale\n- Only include other optional interface fields (icons, brand color) if explicitly provided\n- See references/openai_yaml.md for field definitions and examples\n\n#### Bundled Resources (optional)\n\n##### Scripts (`scripts/`)\n\nExecutable code (Python/Bash/etc.) for tasks that require deterministic reliability or are repeatedly rewritten.\n\n- **When to include**: When the same code is being rewritten repeatedly or deterministic reliability is needed\n- **Example**: `scripts/rotate_pdf.py` for PDF rotation tasks\n- **Benefits**: Token efficient, deterministic, may be executed without loading into context\n- **Note**: Scripts may still need to be read by Codex for patching or environment-specific adjustments\n\n##### References (`references/`)\n\nDocumentation and reference material intended to be loaded as needed into context to inform Codex's process and thinking.\n\n- **When to include**: For documentation that Codex should reference while working\n- **Examples**: `references/finance.md` for financial schemas, `references/mnda.md` for company NDA template, `references/policies.md` for company policies, `references/api_docs.md` for API specifications\n- **Use cases**: Database schemas, API documentation, domain knowledge, company policies, detailed workflow guides\n- **Benefits**: Keeps SKILL.md lean, loaded only when Codex determines it's needed\n- **Best practice**: If files are large (>10k words), include grep search patterns in SKILL.md\n- **Avoid duplication**: Information should live in either SKILL.md or references files, not both. Prefer references files for detailed information unless it's truly core to the skill—this keeps SKILL.md lean while making information discoverable without hogging the context window. Keep only essential procedural instructions and workflow guidance in SKILL.md; move detailed reference material, schemas, and examples to references files.\n\n##### Assets (`assets/`)\n\nFiles not intended to be loaded into context, but rather used within the output Codex produces.\n\n- **When to include**: When the skill needs files that will be used in the final output\n- **Examples**: `assets/logo.png` for brand assets, `assets/slides.pptx` for PowerPoint templates, `assets/frontend-template/` for HTML/React boilerplate, `assets/font.ttf` for typography\n- **Use cases**: Templates, images, icons, boilerplate code, fonts, sample documents that get copied or modified\n- **Benefits**: Separates output resources from documentation, enables Codex to use files without loading them into context\n\n#### What to Not Include in a Skill\n\nA skill should only contain essential files that directly support its functionality. Do NOT create extraneous documentation or auxiliary files, including:\n\n- README.md\n- INSTALLATION_GUIDE.md\n- QUICK_REFERENCE.md\n- CHANGELOG.md\n- etc.\n\nThe skill should only contain the information needed for an AI agent to do the job at hand. It should not contain auxiliary context about the process that went into creating it, setup and testing procedures, user-facing documentation, etc. Creating additional documentation files just adds clutter and confusion.\n\n### Progressive Disclosure Design Principle\n\nSkills use a three-level loading system to manage context efficiently:\n\n1. **Metadata (name + description)** - Always in context (~100 words)\n2. **SKILL.md body** - When skill triggers (<5k words)\n3. **Bundled resources** - As needed by Codex (Unlimited because scripts can be executed without reading into context window)\n\n#### Progressive Disclosure Patterns\n\nKeep SKILL.md body to the essentials and under 500 lines to minimize context bloat. Split content into separate files when approaching this limit. When splitting out content into other files, it is very important to reference them from SKILL.md and describe clearly when to read them, to ensure the reader of the skill knows they exist and when to use them.\n\n**Key principle:** When a skill supports multiple variations, frameworks, or options, keep only the core workflow and selection guidance in SKILL.md. Move variant-specific details (patterns, examples, configuration) into separate reference files.\n\n**Pattern 1: High-level guide with references**\n\n```markdown\n# PDF Processing\n\n## Quick start\n\nExtract text with pdfplumber:\n[code example]\n\n## Advanced features\n\n- **Form filling**: See [FORMS.md](FORMS.md) for complete guide\n- **API reference**: See [REFERENCE.md](REFERENCE.md) for all methods\n- **Examples**: See [EXAMPLES.md](EXAMPLES.md) for common patterns\n```\n\nCodex loads FORMS.md, REFERENCE.md, or EXAMPLES.md only when needed.\n\n**Pattern 2: Domain-specific organization**\n\nFor Skills with multiple domains, organize content by domain to avoid loading irrelevant context:\n\n```\nbigquery-skill/\n├── SKILL.md (overview and navigation)\n└── reference/\n    ├── finance.md (revenue, billing metrics)\n    ├── sales.md (opportunities, pipeline)\n    ├── product.md (API usage, features)\n    └── marketing.md (campaigns, attribution)\n```\n\nWhen a user asks about sales metrics, Codex only reads sales.md.\n\nSimilarly, for skills supporting multiple frameworks or variants, organize by variant:\n\n```\ncloud-deploy/\n├── SKILL.md (workflow + provider selection)\n└── references/\n    ├── aws.md (AWS deployment patterns)\n    ├── gcp.md (GCP deployment patterns)\n    └── azure.md (Azure deployment patterns)\n```\n\nWhen the user chooses AWS, Codex only reads aws.md.\n\n**Pattern 3: Conditional details**\n\nShow basic content, link to advanced content:\n\n```markdown\n# DOCX Processing\n\n## Creating documents\n\nUse docx-js for new documents. See [DOCX-JS.md](DOCX-JS.md).\n\n## Editing documents\n\nFor simple edits, modify the XML directly.\n\n**For tracked changes**: See [REDLINING.md](REDLINING.md)\n**For OOXML details**: See [OOXML.md](OOXML.md)\n```\n\nCodex reads REDLINING.md or OOXML.md only when the user needs those features.\n\n**Important guidelines:**\n\n- **Avoid deeply nested references** - Keep references one level deep from SKILL.md. All reference files should link directly from SKILL.md.\n- **Structure longer reference files** - For files longer than 100 lines, include a table of contents at the top so Codex can see the full scope when previewing.\n\n## Skill Creation Process\n\nSkill creation involves these steps:\n\n1. Understand the skill with concrete examples\n2. Plan reusable skill contents (scripts, references, assets)\n3. Initialize the skill (run init_skill.py)\n4. Edit the skill (implement resources and write SKILL.md)\n5. Validate the skill (run quick_validate.py)\n6. Iterate based on real usage\n\nFollow these steps in order, skipping only if there is a clear reason why they are not applicable.\n\n### Skill Naming\n\n- Use lowercase letters, digits, and hyphens only; normalize user-provided titles to hyphen-case (e.g., \"Plan Mode\" -> `plan-mode`).\n- When generating names, generate a name under 64 characters (letters, digits, hyphens).\n- Prefer short, verb-led phrases that describe the action.\n- Namespace by tool when it improves clarity or triggering (e.g., `gh-address-comments`, `linear-address-issue`).\n- Name the skill folder exactly after the skill name.\n\n### Step 1: Understanding the Skill with Concrete Examples\n\nSkip this step only when the skill's usage patterns are already clearly understood. It remains valuable even when working with an existing skill.\n\nTo create an effective skill, clearly understand concrete examples of how the skill will be used. This understanding can come from either direct user examples or generated examples that are validated with user feedback.\n\nFor example, when building an image-editor skill, relevant questions include:\n\n- \"What functionality should the image-editor skill support? Editing, rotating, anything else?\"\n- \"Can you give some examples of how this skill would be used?\"\n- \"I can imagine users asking for things like 'Remove the red-eye from this image' or 'Rotate this image'. Are there other ways you imagine this skill being used?\"\n- \"What would a user say that should trigger this skill?\"\n\nTo avoid overwhelming users, avoid asking too many questions in a single message. Start with the most important questions and follow up as needed for better effectiveness.\n\nConclude this step when there is a clear sense of the functionality the skill should support.\n\n### Step 2: Planning the Reusable Skill Contents\n\nTo turn concrete examples into an effective skill, analyze each example by:\n\n1. Considering how to execute on the example from scratch\n2. Identifying what scripts, references, and assets would be helpful when executing these workflows repeatedly\n\nExample: When building a `pdf-editor` skill to handle queries like \"Help me rotate this PDF,\" the analysis shows:\n\n1. Rotating a PDF requires re-writing the same code each time\n2. A `scripts/rotate_pdf.py` script would be helpful to store in the skill\n\nExample: When designing a `frontend-webapp-builder` skill for queries like \"Build me a todo app\" or \"Build me a dashboard to track my steps,\" the analysis shows:\n\n1. Writing a frontend webapp requires the same boilerplate HTML/React each time\n2. An `assets/hello-world/` template containing the boilerplate HTML/React project files would be helpful to store in the skill\n\nExample: When building a `big-query` skill to handle queries like \"How many users have logged in today?\" the analysis shows:\n\n1. Querying BigQuery requires re-discovering the table schemas and relationships each time\n2. A `references/schema.md` file documenting the table schemas would be helpful to store in the skill\n\nTo establish the skill's contents, analyze each concrete example to create a list of the reusable resources to include: scripts, references, and assets.\n\n### Step 3: Initializing the Skill\n\nAt this point, it is time to actually create the skill.\n\nSkip this step only if the skill being developed already exists. In this case, continue to the next step.\n\nWhen creating a new skill from scratch, always run the `init_skill.py` script. The script conveniently generates a new template skill directory that automatically includes everything a skill requires, making the skill creation process much more efficient and reliable.\n\nUsage:\n\n```bash\nscripts/init_skill.py <skill-name> --path <output-directory> [--resources scripts,references,assets] [--examples]\n```\n\nExamples:\n\n```bash\nscripts/init_skill.py my-skill --path skills/public\nscripts/init_skill.py my-skill --path skills/public --resources scripts,references\nscripts/init_skill.py my-skill --path skills/public --resources scripts --examples\n```\n\nThe script:\n\n- Creates the skill directory at the specified path\n- Generates a SKILL.md template with proper frontmatter and TODO placeholders\n- Creates `agents/openai.yaml` using agent-generated `display_name`, `short_description`, and `default_prompt` passed via `--interface key=value`\n- Optionally creates resource directories based on `--resources`\n- Optionally adds example files when `--examples` is set\n\nAfter initialization, customize the SKILL.md and add resources as needed. If you used `--examples`, replace or delete placeholder files.\n\nGenerate `display_name`, `short_description`, and `default_prompt` by reading the skill, then pass them as `--interface key=value` to `init_skill.py` or regenerate with:\n\n```bash\nscripts/generate_openai_yaml.py <path/to/skill-folder> --interface key=value\n```\n\nOnly include other optional interface fields when the user explicitly provides them. For full field descriptions and examples, see references/openai_yaml.md.\n\n### Step 4: Edit the Skill\n\nWhen editing the (newly-generated or existing) skill, remember that the skill is being created for another instance of Codex to use. Include information that would be beneficial and non-obvious to Codex. Consider what procedural knowledge, domain-specific details, or reusable assets would help another Codex instance execute these tasks more effectively.\n\n#### Start with Reusable Skill Contents\n\nTo begin implementation, start with the reusable resources identified above: `scripts/`, `references/`, and `assets/` files. Note that this step may require user input. For example, when implementing a `brand-guidelines` skill, the user may need to provide brand assets or templates to store in `assets/`, or documentation to store in `references/`.\n\nAdded scripts must be tested by actually running them to ensure there are no bugs and that the output matches what is expected. If there are many similar scripts, only a representative sample needs to be tested to ensure confidence that they all work while balancing time to completion.\n\nIf you used `--examples`, delete any placeholder files that are not needed for the skill. Only create resource directories that are actually required.\n\n#### Update SKILL.md\n\n**Writing Guidelines:** Always use imperative/infinitive form.\n\n##### Frontmatter\n\nWrite the YAML frontmatter with `name` and `description`:\n\n- `name`: The skill name\n- `description`: This is the primary triggering mechanism for your skill, and helps Codex understand when to use the skill.\n  - Include both what the Skill does and specific triggers/contexts for when to use it.\n  - Include all \"when to use\" information here - Not in the body. The body is only loaded after triggering, so \"When to Use This Skill\" sections in the body are not helpful to Codex.\n  - Example description for a `docx` skill: \"Comprehensive document creation, editing, and analysis with support for tracked changes, comments, formatting preservation, and text extraction. Use when Codex needs to work with professional documents (.docx files) for: (1) Creating new documents, (2) Modifying or editing content, (3) Working with tracked changes, (4) Adding comments, or any other document tasks\"\n\nDo not include any other fields in YAML frontmatter.\n\n##### Body\n\nWrite instructions for using the skill and its bundled resources.\n\n### Step 5: Validate the Skill\n\nOnce development of the skill is complete, validate the skill folder to catch basic issues early:\n\n```bash\nscripts/quick_validate.py <path/to/skill-folder>\n```\n\nThe validation script checks YAML frontmatter format, required fields, and naming rules. If validation fails, fix the reported issues and run the command again.\n\n### Step 6: Iterate\n\nAfter testing the skill, users may request improvements. Often this happens right after using the skill, with fresh context of how the skill performed.\n\n**Iteration workflow:**\n\n1. Use the skill on real tasks\n2. Notice struggles or inefficiencies\n3. Identify how SKILL.md or bundled resources should be updated\n4. Implement changes and test again\n","core/skills/builtin/skill-creator/agents/openai.yaml":"interface:\n  display_name: \"Skill Creator\"\n  short_description: \"Create or update a skill\"\n  default_prompt: \"Read my repository and create a skill to bootstrap new components for my project.\"\n","core/skills/builtin/skill-creator/references/openai_yaml.md":"# openai.yaml fields (full example + descriptions)\n\n`agents/openai.yaml` is an extended, product-specific config intended for the machine/harness to read, not the agent. Other product-specific config can also live in the `agents/` folder.\n\n## Full example\n\n```yaml\ninterface:\n  display_name: \"Optional user-facing name\"\n  short_description: \"Optional user-facing description\"\n  icon_small: \"./assets/small-400px.png\"\n  icon_large: \"./assets/large-logo.svg\"\n  brand_color: \"#3B82F6\"\n  default_prompt: \"Optional surrounding prompt to use the skill with\"\n\ndependencies:\n  tools:\n    - type: \"mcp\"\n      value: \"github\"\n      description: \"GitHub MCP server\"\n      transport: \"streamable_http\"\n      url: \"https://api.githubcopilot.com/mcp/\"\n```\n\n## Field descriptions and constraints\n\nTop-level constraints:\n\n- Quote all string values.\n- Keep keys unquoted.\n- For `interface.default_prompt`: generate a helpful, short (typically 1 sentence) example starting prompt based on the skill. It must explicitly mention the skill as `$skill-name` (e.g., \"Use $skill-name-here to draft a concise weekly status update.\").\n\n- `interface.display_name`: Human-facing title shown in UI skill lists and chips.\n- `interface.short_description`: Human-facing short UI blurb (25–64 chars) for quick scanning.\n- `interface.icon_small`: Path to a small icon asset (relative to skill dir). Default to `./assets/` and place icons in the skill's `assets/` folder.\n- `interface.icon_large`: Path to a larger logo asset (relative to skill dir). Default to `./assets/` and place icons in the skill's `assets/` folder.\n- `interface.brand_color`: Hex color used for UI accents (e.g., badges).\n- `interface.default_prompt`: Default prompt snippet inserted when invoking the skill.\n- `dependencies.tools[].type`: Dependency category. Only `mcp` is supported for now.\n- `dependencies.tools[].value`: Identifier of the tool or dependency.\n- `dependencies.tools[].description`: Human-readable explanation of the dependency.\n- `dependencies.tools[].transport`: Connection type when `type` is `mcp`.\n- `dependencies.tools[].url`: MCP server URL when `type` is `mcp`.\n","core/skills/builtin/webapp-testing/SKILL.md":"---\nname: webapp-testing\ndescription: Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.\nlicense: Complete terms in LICENSE.txt\n---\n\n# Web Application Testing\n\nTo test local web applications, write native Python Playwright scripts.\n\n**Helper Scripts Available**:\n- `scripts/with_server.py` - Manages server lifecycle (supports multiple servers)\n\n**Always run scripts with `--help` first** to see usage. DO NOT read the source until you try running the script first and find that a customized solution is abslutely necessary. These scripts can be very large and thus pollute your context window. They exist to be called directly as black-box scripts rather than ingested into your context window.\n\n## Decision Tree: Choosing Your Approach\n\n```\nUser task → Is it static HTML?\n    ├─ Yes → Read HTML file directly to identify selectors\n    │         ├─ Success → Write Playwright script using selectors\n    │         └─ Fails/Incomplete → Treat as dynamic (below)\n    │\n    └─ No (dynamic webapp) → Is the server already running?\n        ├─ No → Run: python scripts/with_server.py --help\n        │        Then use the helper + write simplified Playwright script\n        │\n        └─ Yes → Reconnaissance-then-action:\n            1. Navigate and wait for networkidle\n            2. Take screenshot or inspect DOM\n            3. Identify selectors from rendered state\n            4. Execute actions with discovered selectors\n```\n\n## Example: Using with_server.py\n\nTo start a server, run `--help` first, then use the helper:\n\n**Single server:**\n```bash\npython scripts/with_server.py --server \"npm run dev\" --port 5173 -- python your_automation.py\n```\n\n**Multiple servers (e.g., backend + frontend):**\n```bash\npython scripts/with_server.py \\\n  --server \"cd backend && python server.py\" --port 3000 \\\n  --server \"cd frontend && npm run dev\" --port 5173 \\\n  -- python your_automation.py\n```\n\nTo create an automation script, include only Playwright logic (servers are managed automatically):\n```python\nfrom playwright.sync_api import sync_playwright\n\nwith sync_playwright() as p:\n    browser = p.chromium.launch(headless=True) # Always launch chromium in headless mode\n    page = browser.new_page()\n    page.goto('http://localhost:5173') # Server already running and ready\n    page.wait_for_load_state('networkidle') # CRITICAL: Wait for JS to execute\n    # ... your automation logic\n    browser.close()\n```\n\n## Reconnaissance-Then-Action Pattern\n\n1. **Inspect rendered DOM**:\n   ```python\n   page.screenshot(path='/tmp/inspect.png', full_page=True)\n   content = page.content()\n   page.locator('button').all()\n   ```\n\n2. **Identify selectors** from inspection results\n\n3. **Execute actions** using discovered selectors\n\n## Common Pitfall\n\n❌ **Don't** inspect the DOM before waiting for `networkidle` on dynamic apps\n✅ **Do** wait for `page.wait_for_load_state('networkidle')` before inspection\n\n## Best Practices\n\n- **Use bundled scripts as black boxes** - To accomplish a task, consider whether one of the scripts available in `scripts/` can help. These scripts handle common, complex workflows reliably without cluttering the context window. Use `--help` to see usage, then invoke directly.\n- Use `sync_playwright()` for synchronous scripts\n- Always close the browser when done\n- Use descriptive selectors: `text=`, `role=`, CSS selectors, or IDs\n- Add appropriate waits: `page.wait_for_selector()` or `page.wait_for_timeout()`\n\n## Reference Files\n\n- **examples/** - Examples showing common patterns:\n  - `element_discovery.py` - Discovering buttons, links, and inputs on a page\n  - `static_html_automation.py` - Using file:// URLs for local HTML\n  - `console_logging.py` - Capturing console logs during automation\n"},"files":{"core/skills/builtin/UPSTREAM_SOURCES.json":"{\n  \"schemaVersion\": 1,\n  \"skills\": {\n    \"frontend-design\": {\n      \"repository\": \"https://github.com/anthropics/skills\",\n      \"revision\": \"f17010c9bb483898c1d9c9f42dde2b3a98889434\",\n      \"path\": \"skills/frontend-design\"\n    },\n    \"mcp-builder\": {\n      \"repository\": \"https://github.com/anthropics/skills\",\n      \"revision\": \"f17010c9bb483898c1d9c9f42dde2b3a98889434\",\n      \"path\": \"skills/mcp-builder\"\n    },\n    \"review-agent\": {\n      \"repository\": \"https://github.com/openai/codex\",\n      \"revision\": \"4ef836f883c38ba6d39e6920f335ce6452b7de33\",\n      \"path\": \"codex-rs/skills/src/assets/samples/review-agent\"\n    },\n    \"security-best-practices\": {\n      \"repository\": \"https://github.com/openai/skills\",\n      \"revision\": \"49f948faa9258a0c61caceaf225e179651397431\",\n      \"path\": \"skills/.curated/security-best-practices\"\n    },\n    \"security-ownership-map\": {\n      \"repository\": \"https://github.com/openai/skills\",\n      \"revision\": \"49f948faa9258a0c61caceaf225e179651397431\",\n      \"path\": \"skills/.curated/security-ownership-map\"\n    },\n    \"security-threat-model\": {\n      \"repository\": \"https://github.com/openai/skills\",\n      \"revision\": \"49f948faa9258a0c61caceaf225e179651397431\",\n      \"path\": \"skills/.curated/security-threat-model\"\n    },\n    \"skill-creator\": {\n      \"repository\": \"https://github.com/openai/skills\",\n      \"revision\": \"49f948faa9258a0c61caceaf225e179651397431\",\n      \"path\": \"skills/.system/skill-creator\"\n    },\n    \"webapp-testing\": {\n      \"repository\": \"https://github.com/anthropics/skills\",\n      \"revision\": \"f17010c9bb483898c1d9c9f42dde2b3a98889434\",\n      \"path\": \"skills/webapp-testing\"\n    }\n  }\n}\n","core/skills/builtin/frontend-design/SKILL.md":"---\nname: frontend-design\ndescription: Guidance for distinctive, intentional visual design when building new UI or reshaping an existing one. Helps with aesthetic direction, typography, and making choices that don't read as templated defaults.\nlicense: Complete terms in LICENSE.txt\n---\n\n# Frontend Design\n\nApproach this as the design lead at a small studio known for giving every client a visual identity that could not be mistaken for anyone else's. This client has already rejected proposals that felt templated, and is paying for a distinctive point of view: make deliberate, opinionated choices about palette, typography, and layout that are specific to this brief, and take one real aesthetic risk you can justify.\n\n## Ground it in the subject\n\nIf the brief does not pin down what the product or subject is, pin it yourself before designing: name one concrete subject, its audience, and the page's single job, and state your choice. If there's any information in your memory about the human's preferences, context about what they're building, or designs you've made before – use that as a hint. The subject's own world, its materials, instruments, artifacts, and vernacular, is where distinctive choices come from. Build with the brief's real content and subject matter throughout.\n\n## Design principles\n\nFor web designs, the hero is a thesis. Open with the most characteristic thing in the subject's world, in whatever form makes sense for it: a headline, an image, an animation, a live demo, an interactive moment. Be deliberate with your choice: a big number with a small label, supporting stats, and a gradient accent is the template answer, only use if that's truly the best option.\n\nTypography carries the personality of the page. Pair the display and body faces deliberately, not the same families you would reach for on any other project, and set a clear type scale with intentional weights, widths, and spacing. Make the type treatment itself a memorable part of the design, not a neutral delivery vehicle for the content.\n\nStructure is information. Structural devices, numbering, eyebrows, dividers, labels, should encode something true about the content, not decorate it. Many generic designs use numbered markers (01 / 02 / 03), but that's only appropriate if the content actually is a sequence - like a real process or a typed timeline where order carries information the reader needs. Question if choices like numbered markers actually make sense before incorporating them.\n\nLeverage motion deliberately. Think about where and if animation can serve the subject: a page-load sequence, a scroll-triggered reveal, hover micro-interactions, ambient atmosphere. An orchestrated moment usually lands harder than scattered effects; choose what the direction calls for. However, sometimes less is more, and extra animation contributes to the feeling that the design is AI-generated.\n\nMatch complexity to the vision. Maximalist directions need elaborate execution; minimal directions need precision in spacing, type, and detail. Elegance is executing the chosen vision well.\n\nConsider written content carefully. Often a design brief may not contain real content, and it's up to you to come up with copy. Copy can make a design feel as templated as the design itself. See the below section on writing for more guidance.\n\n## Process: brainstorm, explore, plan, critique, build, critique again\n\nFor calibration: AI-generated design right now clusters around three looks: (1) a warm cream background (near #F4F1EA) with a high-contrast serif display and a terracotta accent; (2) a near-black background with a single bright acid-green or vermilion accent; (3) a broadsheet-style layout with hairline rules, zero border-radius, and dense newspaper-like columns. All three are legitimate for some briefs, but they are defaults rather than choices, and they appear regardless of subject. Where the brief pins down a visual direction, follow it exactly — the brief's own words always win, including when it asks for one of these looks. Where it leaves an axis free, don't spend that freedom on one of these defaults. Just like a human designer who's hired, there's often a careful balance between doing what you're good at and taking each project as a chance to experiment and learn.\n\nWork in two passes. First, brainstorm a short design plan based on the human's design brief: create a compact token system with color, type, layout, and signature. Color: describe the palette as 4–6 named hex values. Type: the typefaces for 2+ roles (a characterful display face that's used with restraint, a complementary body face, and a utility face for captions or data if needed). Layout: a layout concept, using one-sentence prose descriptions and ASCII wireframes to ideate and compare. Signature: the single unique element this page will be remembered by that embodies the brief in an appropriate way.\n\nThen review that plan against the brief before building: if any part of it reads like the generic default you would produce for any similar page (work through a similar prompt to see if you arrive somewhere similar) rather than a choice made for this specific brief — revise that part, say what you changed and why. Only after you've confirmed the relative uniqueness of your design plan should you start to write the code, following the revised plan exactly and deriving every color and type decision from it.\n\nWhen writing the code, be careful of structuring your CSS selector specificities. It's easy to generate CSS classes that cancel each other out (especially with a type-based selector like .section and a element-based selector like .cta). This can happen often with paddings/margins between sections.\n\nTry to do a lot of this planning and iteration in your thinking, and only show ideas to the user when you have higher confidence it'll delight them.\n\n## Restraint and self-critique\n\nSpend your boldness in one place. Let the signature element be the one memorable thing, keep everything around it quiet and disciplined, and cut any decoration that does not serve the brief. Not taking a risk can be a risk itself! Build to a quality floor without announcing it: responsive down to mobile, visible keyboard focus, reduced motion respected. Critique your own work as you build, taking screenshots if your environment supports it – a picture is worth 1000 tokens. Consider Chanel's advice: before leaving the house, take a look in the mirror and remove one accessory. Human creators have memory and always try to do something new, so if you have a space to quickly jot down notes about what you've tried, it can help you in future passes.\n\n## More on writing in design\n\nWords appear in a design for one reason: to make it easier to understand, and therefore easier to use. They are design material, not decoration. Bring the same intentionality to copy that you would bring to spacing and color. Before writing anything, ask what the design needs to say, and how it can best be said to help the person navigate the experience.\n\nWrite from the end user's side of the screen. Name things by what people control and recognize, never by how the system is built. A person manages notifications, not webhook config. Describe what something does in plain terms rather than selling it. Being specific is always better than being clever.\n\nUse active voice as default. A control should say exactly what happens when it's used: \"Save changes,\" not \"Submit.\" An action keeps the same name through the whole flow, so the button that says \"Publish\" produces a toast that says \"Published.\" The vocabulary of an interface is the signposting for someone navigating the product. Cohesion and consistency are how people learn their way around.\n\nTreat failure and emptiness as moments for direction, not mood. Explain what went wrong and how to fix it, in the interface's voice rather than a person's. Errors don't apologize, and they are never vague about what happened. An empty screen is an invitation to act.\n\nKeep the register conversational and tuned: plain verbs, sentence case, no filler, with tone matched to the brand and the audience. Let each element do exactly one job. A label labels, an example demonstrates, and nothing quietly does double duty.\n","core/skills/builtin/mcp-builder/SKILL.md":"---\nname: mcp-builder\ndescription: Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).\nlicense: Complete terms in LICENSE.txt\n---\n\n# MCP Server Development Guide\n\n## Overview\n\nCreate MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. The quality of an MCP server is measured by how well it enables LLMs to accomplish real-world tasks.\n\n---\n\n# Process\n\n## 🚀 High-Level Workflow\n\nCreating a high-quality MCP server involves four main phases:\n\n### Phase 1: Deep Research and Planning\n\n#### 1.1 Understand Modern MCP Design\n\n**API Coverage vs. Workflow Tools:**\nBalance comprehensive API endpoint coverage with specialized workflow tools. Workflow tools can be more convenient for specific tasks, while comprehensive coverage gives agents flexibility to compose operations. Performance varies by client—some clients benefit from code execution that combines basic tools, while others work better with higher-level workflows. When uncertain, prioritize comprehensive API coverage.\n\n**Tool Naming and Discoverability:**\nClear, descriptive tool names help agents find the right tools quickly. Use consistent prefixes (e.g., `github_create_issue`, `github_list_repos`) and action-oriented naming.\n\n**Context Management:**\nAgents benefit from concise tool descriptions and the ability to filter/paginate results. Design tools that return focused, relevant data. Some clients support code execution which can help agents filter and process data efficiently.\n\n**Actionable Error Messages:**\nError messages should guide agents toward solutions with specific suggestions and next steps.\n\n#### 1.2 Study MCP Protocol Documentation\n\n**Navigate the MCP specification:**\n\nStart with the sitemap to find relevant pages: `https://modelcontextprotocol.io/sitemap.xml`\n\nThen fetch specific pages with `.md` suffix for markdown format (e.g., `https://modelcontextprotocol.io/specification/draft.md`).\n\nKey pages to review:\n- Specification overview and architecture\n- Transport mechanisms (streamable HTTP, stdio)\n- Tool, resource, and prompt definitions\n\n#### 1.3 Study Framework Documentation\n\n**Recommended stack:**\n- **Language**: TypeScript (high-quality SDK support and good compatibility in many execution environments e.g. MCPB. Plus AI models are good at generating TypeScript code, benefiting from its broad usage, static typing and good linting tools)\n- **Transport**: Streamable HTTP for remote servers, using stateless JSON (simpler to scale and maintain, as opposed to stateful sessions and streaming responses). stdio for local servers.\n\n**Load framework documentation:**\n\n- **MCP Best Practices**: [📋 View Best Practices](./reference/mcp_best_practices.md) - Core guidelines\n\n**For TypeScript (recommended):**\n- **TypeScript SDK**: Use WebFetch to load `https://raw.githubusercontent.com/modelcontextprotocol/typescript-sdk/main/README.md`\n- [⚡ TypeScript Guide](./reference/node_mcp_server.md) - TypeScript patterns and examples\n\n**For Python:**\n- **Python SDK**: Use WebFetch to load `https://raw.githubusercontent.com/modelcontextprotocol/python-sdk/main/README.md`\n- [🐍 Python Guide](./reference/python_mcp_server.md) - Python patterns and examples\n\n#### 1.4 Plan Your Implementation\n\n**Understand the API:**\nReview the service's API documentation to identify key endpoints, authentication requirements, and data models. Use web search and WebFetch as needed.\n\n**Tool Selection:**\nPrioritize comprehensive API coverage. List endpoints to implement, starting with the most common operations.\n\n---\n\n### Phase 2: Implementation\n\n#### 2.1 Set Up Project Structure\n\nSee language-specific guides for project setup:\n- [⚡ TypeScript Guide](./reference/node_mcp_server.md) - Project structure, package.json, tsconfig.json\n- [🐍 Python Guide](./reference/python_mcp_server.md) - Module organization, dependencies\n\n#### 2.2 Implement Core Infrastructure\n\nCreate shared utilities:\n- API client with authentication\n- Error handling helpers\n- Response formatting (JSON/Markdown)\n- Pagination support\n\n#### 2.3 Implement Tools\n\nFor each tool:\n\n**Input Schema:**\n- Use Zod (TypeScript) or Pydantic (Python)\n- Include constraints and clear descriptions\n- Add examples in field descriptions\n\n**Output Schema:**\n- Define `outputSchema` where possible for structured data\n- Use `structuredContent` in tool responses (TypeScript SDK feature)\n- Helps clients understand and process tool outputs\n\n**Tool Description:**\n- Concise summary of functionality\n- Parameter descriptions\n- Return type schema\n\n**Implementation:**\n- Async/await for I/O operations\n- Proper error handling with actionable messages\n- Support pagination where applicable\n- Return both text content and structured data when using modern SDKs\n\n**Annotations:**\n- `readOnlyHint`: true/false\n- `destructiveHint`: true/false\n- `idempotentHint`: true/false\n- `openWorldHint`: true/false\n\n---\n\n### Phase 3: Review and Test\n\n#### 3.1 Code Quality\n\nReview for:\n- No duplicated code (DRY principle)\n- Consistent error handling\n- Full type coverage\n- Clear tool descriptions\n\n#### 3.2 Build and Test\n\n**TypeScript:**\n- Run `npm run build` to verify compilation\n- Test with MCP Inspector: `npx @modelcontextprotocol/inspector`\n\n**Python:**\n- Verify syntax: `python -m py_compile your_server.py`\n- Test with MCP Inspector\n\nSee language-specific guides for detailed testing approaches and quality checklists.\n\n---\n\n### Phase 4: Create Evaluations\n\nAfter implementing your MCP server, create comprehensive evaluations to test its effectiveness.\n\n**Load [✅ Evaluation Guide](./reference/evaluation.md) for complete evaluation guidelines.**\n\n#### 4.1 Understand Evaluation Purpose\n\nUse evaluations to test whether LLMs can effectively use your MCP server to answer realistic, complex questions.\n\n#### 4.2 Create 10 Evaluation Questions\n\nTo create effective evaluations, follow the process outlined in the evaluation guide:\n\n1. **Tool Inspection**: List available tools and understand their capabilities\n2. **Content Exploration**: Use READ-ONLY operations to explore available data\n3. **Question Generation**: Create 10 complex, realistic questions\n4. **Answer Verification**: Solve each question yourself to verify answers\n\n#### 4.3 Evaluation Requirements\n\nEnsure each question is:\n- **Independent**: Not dependent on other questions\n- **Read-only**: Only non-destructive operations required\n- **Complex**: Requiring multiple tool calls and deep exploration\n- **Realistic**: Based on real use cases humans would care about\n- **Verifiable**: Single, clear answer that can be verified by string comparison\n- **Stable**: Answer won't change over time\n\n#### 4.4 Output Format\n\nCreate an XML file with this structure:\n\n```xml\n<evaluation>\n  <qa_pair>\n    <question>Find discussions about AI model launches with animal codenames. One model needed a specific safety designation that uses the format ASL-X. What number X was being determined for the model named after a spotted wild cat?</question>\n    <answer>3</answer>\n  </qa_pair>\n<!-- More qa_pairs... -->\n</evaluation>\n```\n\n---\n\n# Reference Files\n\n## 📚 Documentation Library\n\nLoad these resources as needed during development:\n\n### Core MCP Documentation (Load First)\n- **MCP Protocol**: Start with sitemap at `https://modelcontextprotocol.io/sitemap.xml`, then fetch specific pages with `.md` suffix\n- [📋 MCP Best Practices](./reference/mcp_best_practices.md) - Universal MCP guidelines including:\n  - Server and tool naming conventions\n  - Response format guidelines (JSON vs Markdown)\n  - Pagination best practices\n  - Transport selection (streamable HTTP vs stdio)\n  - Security and error handling standards\n\n### SDK Documentation (Load During Phase 1/2)\n- **Python SDK**: Fetch from `https://raw.githubusercontent.com/modelcontextprotocol/python-sdk/main/README.md`\n- **TypeScript SDK**: Fetch from `https://raw.githubusercontent.com/modelcontextprotocol/typescript-sdk/main/README.md`\n\n### Language-Specific Implementation Guides (Load During Phase 2)\n- [🐍 Python Implementation Guide](./reference/python_mcp_server.md) - Complete Python/FastMCP guide with:\n  - Server initialization patterns\n  - Pydantic model examples\n  - Tool registration with `@mcp.tool`\n  - Complete working examples\n  - Quality checklist\n\n- [⚡ TypeScript Implementation Guide](./reference/node_mcp_server.md) - Complete TypeScript guide with:\n  - Project structure\n  - Zod schema patterns\n  - Tool registration with `server.registerTool`\n  - Complete working examples\n  - Quality checklist\n\n### Evaluation Guide (Load During Phase 4)\n- [✅ Evaluation Guide](./reference/evaluation.md) - Complete evaluation creation guide with:\n  - Question creation guidelines\n  - Answer verification strategies\n  - XML format specifications\n  - Example questions and answers\n  - Running an evaluation with the provided scripts\n","core/skills/builtin/mcp-builder/reference/evaluation.md":"# MCP Server Evaluation Guide\n\n## Overview\n\nThis document provides guidance on creating comprehensive evaluations for MCP servers. Evaluations test whether LLMs can effectively use your MCP server to answer realistic, complex questions using only the tools provided.\n\n---\n\n## Quick Reference\n\n### Evaluation Requirements\n- Create 10 human-readable questions\n- Questions must be READ-ONLY, INDEPENDENT, NON-DESTRUCTIVE\n- Each question requires multiple tool calls (potentially dozens)\n- Answers must be single, verifiable values\n- Answers must be STABLE (won't change over time)\n\n### Output Format\n```xml\n<evaluation>\n   <qa_pair>\n      <question>Your question here</question>\n      <answer>Single verifiable answer</answer>\n   </qa_pair>\n</evaluation>\n```\n\n---\n\n## Purpose of Evaluations\n\nThe measure of quality of an MCP server is NOT how well or comprehensively the server implements tools, but how well these implementations (input/output schemas, docstrings/descriptions, functionality) enable LLMs with no other context and access ONLY to the MCP servers to answer realistic and difficult questions.\n\n## Evaluation Overview\n\nCreate 10 human-readable questions requiring ONLY READ-ONLY, INDEPENDENT, NON-DESTRUCTIVE, and IDEMPOTENT operations to answer. Each question should be:\n- Realistic\n- Clear and concise\n- Unambiguous\n- Complex, requiring potentially dozens of tool calls or steps\n- Answerable with a single, verifiable value that you identify in advance\n\n## Question Guidelines\n\n### Core Requirements\n\n1. **Questions MUST be independent**\n   - Each question should NOT depend on the answer to any other question\n   - Should not assume prior write operations from processing another question\n\n2. **Questions MUST require ONLY NON-DESTRUCTIVE AND IDEMPOTENT tool use**\n   - Should not instruct or require modifying state to arrive at the correct answer\n\n3. **Questions must be REALISTIC, CLEAR, CONCISE, and COMPLEX**\n   - Must require another LLM to use multiple (potentially dozens of) tools or steps to answer\n\n### Complexity and Depth\n\n4. **Questions must require deep exploration**\n   - Consider multi-hop questions requiring multiple sub-questions and sequential tool calls\n   - Each step should benefit from information found in previous questions\n\n5. **Questions may require extensive paging**\n   - May need paging through multiple pages of results\n   - May require querying old data (1-2 years out-of-date) to find niche information\n   - The questions must be DIFFICULT\n\n6. **Questions must require deep understanding**\n   - Rather than surface-level knowledge\n   - May pose complex ideas as True/False questions requiring evidence\n   - May use multiple-choice format where LLM must search different hypotheses\n\n7. **Questions must not be solvable with straightforward keyword search**\n   - Do not include specific keywords from the target content\n   - Use synonyms, related concepts, or paraphrases\n   - Require multiple searches, analyzing multiple related items, extracting context, then deriving the answer\n\n### Tool Testing\n\n8. **Questions should stress-test tool return values**\n   - May elicit tools returning large JSON objects or lists, overwhelming the LLM\n   - Should require understanding multiple modalities of data:\n     - IDs and names\n     - Timestamps and datetimes (months, days, years, seconds)\n     - File IDs, names, extensions, and mimetypes\n     - URLs, GIDs, etc.\n   - Should probe the tool's ability to return all useful forms of data\n\n9. **Questions should MOSTLY reflect real human use cases**\n   - The kinds of information retrieval tasks that HUMANS assisted by an LLM would care about\n\n10. **Questions may require dozens of tool calls**\n    - This challenges LLMs with limited context\n    - Encourages MCP server tools to reduce information returned\n\n11. **Include ambiguous questions**\n    - May be ambiguous OR require difficult decisions on which tools to call\n    - Force the LLM to potentially make mistakes or misinterpret\n    - Ensure that despite AMBIGUITY, there is STILL A SINGLE VERIFIABLE ANSWER\n\n### Stability\n\n12. **Questions must be designed so the answer DOES NOT CHANGE**\n    - Do not ask questions that rely on \"current state\" which is dynamic\n    - For example, do not count:\n      - Number of reactions to a post\n      - Number of replies to a thread\n      - Number of members in a channel\n\n13. **DO NOT let the MCP server RESTRICT the kinds of questions you create**\n    - Create challenging and complex questions\n    - Some may not be solvable with the available MCP server tools\n    - Questions may require specific output formats (datetime vs. epoch time, JSON vs. MARKDOWN)\n    - Questions may require dozens of tool calls to complete\n\n## Answer Guidelines\n\n### Verification\n\n1. **Answers must be VERIFIABLE via direct string comparison**\n   - If the answer can be re-written in many formats, clearly specify the output format in the QUESTION\n   - Examples: \"Use YYYY/MM/DD.\", \"Respond True or False.\", \"Answer A, B, C, or D and nothing else.\"\n   - Answer should be a single VERIFIABLE value such as:\n     - User ID, user name, display name, first name, last name\n     - Channel ID, channel name\n     - Message ID, string\n     - URL, title\n     - Numerical quantity\n     - Timestamp, datetime\n     - Boolean (for True/False questions)\n     - Email address, phone number\n     - File ID, file name, file extension\n     - Multiple choice answer\n   - Answers must not require special formatting or complex, structured output\n   - Answer will be verified using DIRECT STRING COMPARISON\n\n### Readability\n\n2. **Answers should generally prefer HUMAN-READABLE formats**\n   - Examples: names, first name, last name, datetime, file name, message string, URL, yes/no, true/false, a/b/c/d\n   - Rather than opaque IDs (though IDs are acceptable)\n   - The VAST MAJORITY of answers should be human-readable\n\n### Stability\n\n3. **Answers must be STABLE/STATIONARY**\n   - Look at old content (e.g., conversations that have ended, projects that have launched, questions answered)\n   - Create QUESTIONS based on \"closed\" concepts that will always return the same answer\n   - Questions may ask to consider a fixed time window to insulate from non-stationary answers\n   - Rely on context UNLIKELY to change\n   - Example: if finding a paper name, be SPECIFIC enough so answer is not confused with papers published later\n\n4. **Answers must be CLEAR and UNAMBIGUOUS**\n   - Questions must be designed so there is a single, clear answer\n   - Answer can be derived from using the MCP server tools\n\n### Diversity\n\n5. **Answers must be DIVERSE**\n   - Answer should be a single VERIFIABLE value in diverse modalities and formats\n   - User concept: user ID, user name, display name, first name, last name, email address, phone number\n   - Channel concept: channel ID, channel name, channel topic\n   - Message concept: message ID, message string, timestamp, month, day, year\n\n6. **Answers must NOT be complex structures**\n   - Not a list of values\n   - Not a complex object\n   - Not a list of IDs or strings\n   - Not natural language text\n   - UNLESS the answer can be straightforwardly verified using DIRECT STRING COMPARISON\n   - And can be realistically reproduced\n   - It should be unlikely that an LLM would return the same list in any other order or format\n\n## Evaluation Process\n\n### Step 1: Documentation Inspection\n\nRead the documentation of the target API to understand:\n- Available endpoints and functionality\n- If ambiguity exists, fetch additional information from the web\n- Parallelize this step AS MUCH AS POSSIBLE\n- Ensure each subagent is ONLY examining documentation from the file system or on the web\n\n### Step 2: Tool Inspection\n\nList the tools available in the MCP server:\n- Inspect the MCP server directly\n- Understand input/output schemas, docstrings, and descriptions\n- WITHOUT calling the tools themselves at this stage\n\n### Step 3: Developing Understanding\n\nRepeat steps 1 & 2 until you have a good understanding:\n- Iterate multiple times\n- Think about the kinds of tasks you want to create\n- Refine your understanding\n- At NO stage should you READ the code of the MCP server implementation itself\n- Use your intuition and understanding to create reasonable, realistic, but VERY challenging tasks\n\n### Step 4: Read-Only Content Inspection\n\nAfter understanding the API and tools, USE the MCP server tools:\n- Inspect content using READ-ONLY and NON-DESTRUCTIVE operations ONLY\n- Goal: identify specific content (e.g., users, channels, messages, projects, tasks) for creating realistic questions\n- Should NOT call any tools that modify state\n- Will NOT read the code of the MCP server implementation itself\n- Parallelize this step with individual sub-agents pursuing independent explorations\n- Ensure each subagent is only performing READ-ONLY, NON-DESTRUCTIVE, and IDEMPOTENT operations\n- BE CAREFUL: SOME TOOLS may return LOTS OF DATA which would cause you to run out of CONTEXT\n- Make INCREMENTAL, SMALL, AND TARGETED tool calls for exploration\n- In all tool call requests, use the `limit` parameter to limit results (<10)\n- Use pagination\n\n### Step 5: Task Generation\n\nAfter inspecting the content, create 10 human-readable questions:\n- An LLM should be able to answer these with the MCP server\n- Follow all question and answer guidelines above\n\n## Output Format\n\nEach QA pair consists of a question and an answer. The output should be an XML file with this structure:\n\n```xml\n<evaluation>\n   <qa_pair>\n      <question>Find the project created in Q2 2024 with the highest number of completed tasks. What is the project name?</question>\n      <answer>Website Redesign</answer>\n   </qa_pair>\n   <qa_pair>\n      <question>Search for issues labeled as \"bug\" that were closed in March 2024. Which user closed the most issues? Provide their username.</question>\n      <answer>sarah_dev</answer>\n   </qa_pair>\n   <qa_pair>\n      <question>Look for pull requests that modified files in the /api directory and were merged between January 1 and January 31, 2024. How many different contributors worked on these PRs?</question>\n      <answer>7</answer>\n   </qa_pair>\n   <qa_pair>\n      <question>Find the repository with the most stars that was created before 2023. What is the repository name?</question>\n      <answer>data-pipeline</answer>\n   </qa_pair>\n</evaluation>\n```\n\n## Evaluation Examples\n\n### Good Questions\n\n**Example 1: Multi-hop question requiring deep exploration (GitHub MCP)**\n```xml\n<qa_pair>\n   <question>Find the repository that was archived in Q3 2023 and had previously been the most forked project in the organization. What was the primary programming language used in that repository?</question>\n   <answer>Python</answer>\n</qa_pair>\n```\n\nThis question is good because:\n- Requires multiple searches to find archived repositories\n- Needs to identify which had the most forks before archival\n- Requires examining repository details for the language\n- Answer is a simple, verifiable value\n- Based on historical (closed) data that won't change\n\n**Example 2: Requires understanding context without keyword matching (Project Management MCP)**\n```xml\n<qa_pair>\n   <question>Locate the initiative focused on improving customer onboarding that was completed in late 2023. The project lead created a retrospective document after completion. What was the lead's role title at that time?</question>\n   <answer>Product Manager</answer>\n</qa_pair>\n```\n\nThis question is good because:\n- Doesn't use specific project name (\"initiative focused on improving customer onboarding\")\n- Requires finding completed projects from specific timeframe\n- Needs to identify the project lead and their role\n- Requires understanding context from retrospective documents\n- Answer is human-readable and stable\n- Based on completed work (won't change)\n\n**Example 3: Complex aggregation requiring multiple steps (Issue Tracker MCP)**\n```xml\n<qa_pair>\n   <question>Among all bugs reported in January 2024 that were marked as critical priority, which assignee resolved the highest percentage of their assigned bugs within 48 hours? Provide the assignee's username.</question>\n   <answer>alex_eng</answer>\n</qa_pair>\n```\n\nThis question is good because:\n- Requires filtering bugs by date, priority, and status\n- Needs to group by assignee and calculate resolution rates\n- Requires understanding timestamps to determine 48-hour windows\n- Tests pagination (potentially many bugs to process)\n- Answer is a single username\n- Based on historical data from specific time period\n\n**Example 4: Requires synthesis across multiple data types (CRM MCP)**\n```xml\n<qa_pair>\n   <question>Find the account that upgraded from the Starter to Enterprise plan in Q4 2023 and had the highest annual contract value. What industry does this account operate in?</question>\n   <answer>Healthcare</answer>\n</qa_pair>\n```\n\nThis question is good because:\n- Requires understanding subscription tier changes\n- Needs to identify upgrade events in specific timeframe\n- Requires comparing contract values\n- Must access account industry information\n- Answer is simple and verifiable\n- Based on completed historical transactions\n\n### Poor Questions\n\n**Example 1: Answer changes over time**\n```xml\n<qa_pair>\n   <question>How many open issues are currently assigned to the engineering team?</question>\n   <answer>47</answer>\n</qa_pair>\n```\n\nThis question is poor because:\n- The answer will change as issues are created, closed, or reassigned\n- Not based on stable/stationary data\n- Relies on \"current state\" which is dynamic\n\n**Example 2: Too easy with keyword search**\n```xml\n<qa_pair>\n   <question>Find the pull request with title \"Add authentication feature\" and tell me who created it.</question>\n   <answer>developer123</answer>\n</qa_pair>\n```\n\nThis question is poor because:\n- Can be solved with a straightforward keyword search for exact title\n- Doesn't require deep exploration or understanding\n- No synthesis or analysis needed\n\n**Example 3: Ambiguous answer format**\n```xml\n<qa_pair>\n   <question>List all the repositories that have Python as their primary language.</question>\n   <answer>repo1, repo2, repo3, data-pipeline, ml-tools</answer>\n</qa_pair>\n```\n\nThis question is poor because:\n- Answer is a list that could be returned in any order\n- Difficult to verify with direct string comparison\n- LLM might format differently (JSON array, comma-separated, newline-separated)\n- Better to ask for a specific aggregate (count) or superlative (most stars)\n\n## Verification Process\n\nAfter creating evaluations:\n\n1. **Examine the XML file** to understand the schema\n2. **Load each task instruction** and in parallel using the MCP server and tools, identify the correct answer by attempting to solve the task YOURSELF\n3. **Flag any operations** that require WRITE or DESTRUCTIVE operations\n4. **Accumulate all CORRECT answers** and replace any incorrect answers in the document\n5. **Remove any `<qa_pair>`** that require WRITE or DESTRUCTIVE operations\n\nRemember to parallelize solving tasks to avoid running out of context, then accumulate all answers and make changes to the file at the end.\n\n## Tips for Creating Quality Evaluations\n\n1. **Think Hard and Plan Ahead** before generating tasks\n2. **Parallelize Where Opportunity Arises** to speed up the process and manage context\n3. **Focus on Realistic Use Cases** that humans would actually want to accomplish\n4. **Create Challenging Questions** that test the limits of the MCP server's capabilities\n5. **Ensure Stability** by using historical data and closed concepts\n6. **Verify Answers** by solving the questions yourself using the MCP server tools\n7. **Iterate and Refine** based on what you learn during the process\n\n---\n\n# Running Evaluations\n\nAfter creating your evaluation file, you can use the provided evaluation harness to test your MCP server.\n\n## Setup\n\n1. **Install Dependencies**\n\n   ```bash\n   pip install -r scripts/requirements.txt\n   ```\n\n   Or install manually:\n   ```bash\n   pip install anthropic mcp\n   ```\n\n2. **Set API Key**\n\n   ```bash\n   export ANTHROPIC_API_KEY=your_api_key_here\n   ```\n\n## Evaluation File Format\n\nEvaluation files use XML format with `<qa_pair>` elements:\n\n```xml\n<evaluation>\n   <qa_pair>\n      <question>Find the project created in Q2 2024 with the highest number of completed tasks. What is the project name?</question>\n      <answer>Website Redesign</answer>\n   </qa_pair>\n   <qa_pair>\n      <question>Search for issues labeled as \"bug\" that were closed in March 2024. Which user closed the most issues? Provide their username.</question>\n      <answer>sarah_dev</answer>\n   </qa_pair>\n</evaluation>\n```\n\n## Running Evaluations\n\nThe evaluation script (`scripts/evaluation.py`) supports three transport types:\n\n**Important:**\n- **stdio transport**: The evaluation script automatically launches and manages the MCP server process for you. Do not run the server manually.\n- **sse/http transports**: You must start the MCP server separately before running the evaluation. The script connects to the already-running server at the specified URL.\n\n### 1. Local STDIO Server\n\nFor locally-run MCP servers (script launches the server automatically):\n\n```bash\npython scripts/evaluation.py \\\n  -t stdio \\\n  -c python \\\n  -a my_mcp_server.py \\\n  evaluation.xml\n```\n\nWith environment variables:\n```bash\npython scripts/evaluation.py \\\n  -t stdio \\\n  -c python \\\n  -a my_mcp_server.py \\\n  -e API_KEY=abc123 \\\n  -e DEBUG=true \\\n  evaluation.xml\n```\n\n### 2. Server-Sent Events (SSE)\n\nFor SSE-based MCP servers (you must start the server first):\n\n```bash\npython scripts/evaluation.py \\\n  -t sse \\\n  -u https://example.com/mcp \\\n  -H \"Authorization: Bearer token123\" \\\n  -H \"X-Custom-Header: value\" \\\n  evaluation.xml\n```\n\n### 3. HTTP (Streamable HTTP)\n\nFor HTTP-based MCP servers (you must start the server first):\n\n```bash\npython scripts/evaluation.py \\\n  -t http \\\n  -u https://example.com/mcp \\\n  -H \"Authorization: Bearer token123\" \\\n  evaluation.xml\n```\n\n## Command-Line Options\n\n```\nusage: evaluation.py [-h] [-t {stdio,sse,http}] [-m MODEL] [-c COMMAND]\n                     [-a ARGS [ARGS ...]] [-e ENV [ENV ...]] [-u URL]\n                     [-H HEADERS [HEADERS ...]] [-o OUTPUT]\n                     eval_file\n\npositional arguments:\n  eval_file             Path to evaluation XML file\n\noptional arguments:\n  -h, --help            Show help message\n  -t, --transport       Transport type: stdio, sse, or http (default: stdio)\n  -m, --model           Claude model to use (default: claude-3-7-sonnet-20250219)\n  -o, --output          Output file for report (default: print to stdout)\n\nstdio options:\n  -c, --command         Command to run MCP server (e.g., python, node)\n  -a, --args            Arguments for the command (e.g., server.py)\n  -e, --env             Environment variables in KEY=VALUE format\n\nsse/http options:\n  -u, --url             MCP server URL\n  -H, --header          HTTP headers in 'Key: Value' format\n```\n\n## Output\n\nThe evaluation script generates a detailed report including:\n\n- **Summary Statistics**:\n  - Accuracy (correct/total)\n  - Average task duration\n  - Average tool calls per task\n  - Total tool calls\n\n- **Per-Task Results**:\n  - Prompt and expected response\n  - Actual response from the agent\n  - Whether the answer was correct (✅/❌)\n  - Duration and tool call details\n  - Agent's summary of its approach\n  - Agent's feedback on the tools\n\n### Save Report to File\n\n```bash\npython scripts/evaluation.py \\\n  -t stdio \\\n  -c python \\\n  -a my_server.py \\\n  -o evaluation_report.md \\\n  evaluation.xml\n```\n\n## Complete Example Workflow\n\nHere's a complete example of creating and running an evaluation:\n\n1. **Create your evaluation file** (`my_evaluation.xml`):\n\n```xml\n<evaluation>\n   <qa_pair>\n      <question>Find the user who created the most issues in January 2024. What is their username?</question>\n      <answer>alice_developer</answer>\n   </qa_pair>\n   <qa_pair>\n      <question>Among all pull requests merged in Q1 2024, which repository had the highest number? Provide the repository name.</question>\n      <answer>backend-api</answer>\n   </qa_pair>\n   <qa_pair>\n      <question>Find the project that was completed in December 2023 and had the longest duration from start to finish. How many days did it take?</question>\n      <answer>127</answer>\n   </qa_pair>\n</evaluation>\n```\n\n2. **Install dependencies**:\n\n```bash\npip install -r scripts/requirements.txt\nexport ANTHROPIC_API_KEY=your_api_key\n```\n\n3. **Run evaluation**:\n\n```bash\npython scripts/evaluation.py \\\n  -t stdio \\\n  -c python \\\n  -a github_mcp_server.py \\\n  -e GITHUB_TOKEN=ghp_xxx \\\n  -o github_eval_report.md \\\n  my_evaluation.xml\n```\n\n4. **Review the report** in `github_eval_report.md` to:\n   - See which questions passed/failed\n   - Read the agent's feedback on your tools\n   - Identify areas for improvement\n   - Iterate on your MCP server design\n\n## Troubleshooting\n\n### Connection Errors\n\nIf you get connection errors:\n- **STDIO**: Verify the command and arguments are correct\n- **SSE/HTTP**: Check the URL is accessible and headers are correct\n- Ensure any required API keys are set in environment variables or headers\n\n### Low Accuracy\n\nIf many evaluations fail:\n- Review the agent's feedback for each task\n- Check if tool descriptions are clear and comprehensive\n- Verify input parameters are well-documented\n- Consider whether tools return too much or too little data\n- Ensure error messages are actionable\n\n### Timeout Issues\n\nIf tasks are timing out:\n- Use a more capable model (e.g., `claude-3-7-sonnet-20250219`)\n- Check if tools are returning too much data\n- Verify pagination is working correctly\n- Consider simplifying complex questions\n","core/skills/builtin/mcp-builder/reference/mcp_best_practices.md":"# MCP Server Best Practices\n\n## Quick Reference\n\n### Server Naming\n- **Python**: `{service}_mcp` (e.g., `slack_mcp`)\n- **Node/TypeScript**: `{service}-mcp-server` (e.g., `slack-mcp-server`)\n\n### Tool Naming\n- Use snake_case with service prefix\n- Format: `{service}_{action}_{resource}`\n- Example: `slack_send_message`, `github_create_issue`\n\n### Response Formats\n- Support both JSON and Markdown formats\n- JSON for programmatic processing\n- Markdown for human readability\n\n### Pagination\n- Always respect `limit` parameter\n- Return `has_more`, `next_offset`, `total_count`\n- Default to 20-50 items\n\n### Transport\n- **Streamable HTTP**: For remote servers, multi-client scenarios\n- **stdio**: For local integrations, command-line tools\n- Avoid SSE (deprecated in favor of streamable HTTP)\n\n---\n\n## Server Naming Conventions\n\nFollow these standardized naming patterns:\n\n**Python**: Use format `{service}_mcp` (lowercase with underscores)\n- Examples: `slack_mcp`, `github_mcp`, `jira_mcp`\n\n**Node/TypeScript**: Use format `{service}-mcp-server` (lowercase with hyphens)\n- Examples: `slack-mcp-server`, `github-mcp-server`, `jira-mcp-server`\n\nThe name should be general, descriptive of the service being integrated, easy to infer from the task description, and without version numbers.\n\n---\n\n## Tool Naming and Design\n\n### Tool Naming\n\n1. **Use snake_case**: `search_users`, `create_project`, `get_channel_info`\n2. **Include service prefix**: Anticipate that your MCP server may be used alongside other MCP servers\n   - Use `slack_send_message` instead of just `send_message`\n   - Use `github_create_issue` instead of just `create_issue`\n3. **Be action-oriented**: Start with verbs (get, list, search, create, etc.)\n4. **Be specific**: Avoid generic names that could conflict with other servers\n\n### Tool Design\n\n- Tool descriptions must narrowly and unambiguously describe functionality\n- Descriptions must precisely match actual functionality\n- Provide tool annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint)\n- Keep tool operations focused and atomic\n\n---\n\n## Response Formats\n\nAll tools that return data should support multiple formats:\n\n### JSON Format (`response_format=\"json\"`)\n- Machine-readable structured data\n- Include all available fields and metadata\n- Consistent field names and types\n- Use for programmatic processing\n\n### Markdown Format (`response_format=\"markdown\"`, typically default)\n- Human-readable formatted text\n- Use headers, lists, and formatting for clarity\n- Convert timestamps to human-readable format\n- Show display names with IDs in parentheses\n- Omit verbose metadata\n\n---\n\n## Pagination\n\nFor tools that list resources:\n\n- **Always respect the `limit` parameter**\n- **Implement pagination**: Use `offset` or cursor-based pagination\n- **Return pagination metadata**: Include `has_more`, `next_offset`/`next_cursor`, `total_count`\n- **Never load all results into memory**: Especially important for large datasets\n- **Default to reasonable limits**: 20-50 items is typical\n\nExample pagination response:\n```json\n{\n  \"total\": 150,\n  \"count\": 20,\n  \"offset\": 0,\n  \"items\": [...],\n  \"has_more\": true,\n  \"next_offset\": 20\n}\n```\n\n---\n\n## Transport Options\n\n### Streamable HTTP\n\n**Best for**: Remote servers, web services, multi-client scenarios\n\n**Characteristics**:\n- Bidirectional communication over HTTP\n- Supports multiple simultaneous clients\n- Can be deployed as a web service\n- Enables server-to-client notifications\n\n**Use when**:\n- Serving multiple clients simultaneously\n- Deploying as a cloud service\n- Integration with web applications\n\n### stdio\n\n**Best for**: Local integrations, command-line tools\n\n**Characteristics**:\n- Standard input/output stream communication\n- Simple setup, no network configuration needed\n- Runs as a subprocess of the client\n\n**Use when**:\n- Building tools for local development environments\n- Integrating with desktop applications\n- Single-user, single-session scenarios\n\n**Note**: stdio servers should NOT log to stdout (use stderr for logging)\n\n### Transport Selection\n\n| Criterion | stdio | Streamable HTTP |\n|-----------|-------|-----------------|\n| **Deployment** | Local | Remote |\n| **Clients** | Single | Multiple |\n| **Complexity** | Low | Medium |\n| **Real-time** | No | Yes |\n\n---\n\n## Security Best Practices\n\n### Authentication and Authorization\n\n**OAuth 2.1**:\n- Use secure OAuth 2.1 with certificates from recognized authorities\n- Validate access tokens before processing requests\n- Only accept tokens specifically intended for your server\n\n**API Keys**:\n- Store API keys in environment variables, never in code\n- Validate keys on server startup\n- Provide clear error messages when authentication fails\n\n### Input Validation\n\n- Sanitize file paths to prevent directory traversal\n- Validate URLs and external identifiers\n- Check parameter sizes and ranges\n- Prevent command injection in system calls\n- Use schema validation (Pydantic/Zod) for all inputs\n\n### Error Handling\n\n- Don't expose internal errors to clients\n- Log security-relevant errors server-side\n- Provide helpful but not revealing error messages\n- Clean up resources after errors\n\n### DNS Rebinding Protection\n\nFor streamable HTTP servers running locally:\n- Enable DNS rebinding protection\n- Validate the `Origin` header on all incoming connections\n- Bind to `127.0.0.1` rather than `0.0.0.0`\n\n---\n\n## Tool Annotations\n\nProvide annotations to help clients understand tool behavior:\n\n| Annotation | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `readOnlyHint` | boolean | false | Tool does not modify its environment |\n| `destructiveHint` | boolean | true | Tool may perform destructive updates |\n| `idempotentHint` | boolean | false | Repeated calls with same args have no additional effect |\n| `openWorldHint` | boolean | true | Tool interacts with external entities |\n\n**Important**: Annotations are hints, not security guarantees. Clients should not make security-critical decisions based solely on annotations.\n\n---\n\n## Error Handling\n\n- Use standard JSON-RPC error codes\n- Report tool errors within result objects (not protocol-level errors)\n- Provide helpful, specific error messages with suggested next steps\n- Don't expose internal implementation details\n- Clean up resources properly on errors\n\nExample error handling:\n```typescript\ntry {\n  const result = performOperation();\n  return { content: [{ type: \"text\", text: result }] };\n} catch (error) {\n  return {\n    isError: true,\n    content: [{\n      type: \"text\",\n      text: `Error: ${error.message}. Try using filter='active_only' to reduce results.`\n    }]\n  };\n}\n```\n\n---\n\n## Testing Requirements\n\nComprehensive testing should cover:\n\n- **Functional testing**: Verify correct execution with valid/invalid inputs\n- **Integration testing**: Test interaction with external systems\n- **Security testing**: Validate auth, input sanitization, rate limiting\n- **Performance testing**: Check behavior under load, timeouts\n- **Error handling**: Ensure proper error reporting and cleanup\n\n---\n\n## Documentation Requirements\n\n- Provide clear documentation of all tools and capabilities\n- Include working examples (at least 3 per major feature)\n- Document security considerations\n- Specify required permissions and access levels\n- Document rate limits and performance characteristics\n","core/skills/builtin/mcp-builder/reference/node_mcp_server.md":"# Node/TypeScript MCP Server Implementation Guide\n\n## Overview\n\nThis document provides Node/TypeScript-specific best practices and examples for implementing MCP servers using the MCP TypeScript SDK. It covers project structure, server setup, tool registration patterns, input validation with Zod, error handling, and complete working examples.\n\n---\n\n## Quick Reference\n\n### Key Imports\n```typescript\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport express from \"express\";\nimport { z } from \"zod\";\n```\n\n### Server Initialization\n```typescript\nconst server = new McpServer({\n  name: \"service-mcp-server\",\n  version: \"1.0.0\"\n});\n```\n\n### Tool Registration Pattern\n```typescript\nserver.registerTool(\n  \"tool_name\",\n  {\n    title: \"Tool Display Name\",\n    description: \"What the tool does\",\n    inputSchema: { param: z.string() },\n    outputSchema: { result: z.string() }\n  },\n  async ({ param }) => {\n    const output = { result: `Processed: ${param}` };\n    return {\n      content: [{ type: \"text\", text: JSON.stringify(output) }],\n      structuredContent: output // Modern pattern for structured data\n    };\n  }\n);\n```\n\n---\n\n## MCP TypeScript SDK\n\nThe official MCP TypeScript SDK provides:\n- `McpServer` class for server initialization\n- `registerTool` method for tool registration\n- Zod schema integration for runtime input validation\n- Type-safe tool handler implementations\n\n**IMPORTANT - Use Modern APIs Only:**\n- **DO use**: `server.registerTool()`, `server.registerResource()`, `server.registerPrompt()`\n- **DO NOT use**: Old deprecated APIs such as `server.tool()`, `server.setRequestHandler(ListToolsRequestSchema, ...)`, or manual handler registration\n- The `register*` methods provide better type safety, automatic schema handling, and are the recommended approach\n\nSee the MCP SDK documentation in the references for complete details.\n\n## Server Naming Convention\n\nNode/TypeScript MCP servers must follow this naming pattern:\n- **Format**: `{service}-mcp-server` (lowercase with hyphens)\n- **Examples**: `github-mcp-server`, `jira-mcp-server`, `stripe-mcp-server`\n\nThe name should be:\n- General (not tied to specific features)\n- Descriptive of the service/API being integrated\n- Easy to infer from the task description\n- Without version numbers or dates\n\n## Project Structure\n\nCreate the following structure for Node/TypeScript MCP servers:\n\n```\n{service}-mcp-server/\n├── package.json\n├── tsconfig.json\n├── README.md\n├── src/\n│   ├── index.ts          # Main entry point with McpServer initialization\n│   ├── types.ts          # TypeScript type definitions and interfaces\n│   ├── tools/            # Tool implementations (one file per domain)\n│   ├── services/         # API clients and shared utilities\n│   ├── schemas/          # Zod validation schemas\n│   └── constants.ts      # Shared constants (API_URL, CHARACTER_LIMIT, etc.)\n└── dist/                 # Built JavaScript files (entry point: dist/index.js)\n```\n\n## Tool Implementation\n\n### Tool Naming\n\nUse snake_case for tool names (e.g., \"search_users\", \"create_project\", \"get_channel_info\") with clear, action-oriented names.\n\n**Avoid Naming Conflicts**: Include the service context to prevent overlaps:\n- Use \"slack_send_message\" instead of just \"send_message\"\n- Use \"github_create_issue\" instead of just \"create_issue\"\n- Use \"asana_list_tasks\" instead of just \"list_tasks\"\n\n### Tool Structure\n\nTools are registered using the `registerTool` method with the following requirements:\n- Use Zod schemas for runtime input validation and type safety\n- The `description` field must be explicitly provided - JSDoc comments are NOT automatically extracted\n- Explicitly provide `title`, `description`, `inputSchema`, and `annotations`\n- The `inputSchema` must be a Zod schema object (not a JSON schema)\n- Type all parameters and return values explicitly\n\n```typescript\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\n\nconst server = new McpServer({\n  name: \"example-mcp\",\n  version: \"1.0.0\"\n});\n\n// Zod schema for input validation\nconst UserSearchInputSchema = z.object({\n  query: z.string()\n    .min(2, \"Query must be at least 2 characters\")\n    .max(200, \"Query must not exceed 200 characters\")\n    .describe(\"Search string to match against names/emails\"),\n  limit: z.number()\n    .int()\n    .min(1)\n    .max(100)\n    .default(20)\n    .describe(\"Maximum results to return\"),\n  offset: z.number()\n    .int()\n    .min(0)\n    .default(0)\n    .describe(\"Number of results to skip for pagination\"),\n  response_format: z.nativeEnum(ResponseFormat)\n    .default(ResponseFormat.MARKDOWN)\n    .describe(\"Output format: 'markdown' for human-readable or 'json' for machine-readable\")\n}).strict();\n\n// Type definition from Zod schema\ntype UserSearchInput = z.infer<typeof UserSearchInputSchema>;\n\nserver.registerTool(\n  \"example_search_users\",\n  {\n    title: \"Search Example Users\",\n    description: `Search for users in the Example system by name, email, or team.\n\nThis tool searches across all user profiles in the Example platform, supporting partial matches and various search filters. It does NOT create or modify users, only searches existing ones.\n\nArgs:\n  - query (string): Search string to match against names/emails\n  - limit (number): Maximum results to return, between 1-100 (default: 20)\n  - offset (number): Number of results to skip for pagination (default: 0)\n  - response_format ('markdown' | 'json'): Output format (default: 'markdown')\n\nReturns:\n  For JSON format: Structured data with schema:\n  {\n    \"total\": number,           // Total number of matches found\n    \"count\": number,           // Number of results in this response\n    \"offset\": number,          // Current pagination offset\n    \"users\": [\n      {\n        \"id\": string,          // User ID (e.g., \"U123456789\")\n        \"name\": string,        // Full name (e.g., \"John Doe\")\n        \"email\": string,       // Email address\n        \"team\": string,        // Team name (optional)\n        \"active\": boolean      // Whether user is active\n      }\n    ],\n    \"has_more\": boolean,       // Whether more results are available\n    \"next_offset\": number      // Offset for next page (if has_more is true)\n  }\n\nExamples:\n  - Use when: \"Find all marketing team members\" -> params with query=\"team:marketing\"\n  - Use when: \"Search for John's account\" -> params with query=\"john\"\n  - Don't use when: You need to create a user (use example_create_user instead)\n\nError Handling:\n  - Returns \"Error: Rate limit exceeded\" if too many requests (429 status)\n  - Returns \"No users found matching '<query>'\" if search returns empty`,\n    inputSchema: UserSearchInputSchema,\n    annotations: {\n      readOnlyHint: true,\n      destructiveHint: false,\n      idempotentHint: true,\n      openWorldHint: true\n    }\n  },\n  async (params: UserSearchInput) => {\n    try {\n      // Input validation is handled by Zod schema\n      // Make API request using validated parameters\n      const data = await makeApiRequest<any>(\n        \"users/search\",\n        \"GET\",\n        undefined,\n        {\n          q: params.query,\n          limit: params.limit,\n          offset: params.offset\n        }\n      );\n\n      const users = data.users || [];\n      const total = data.total || 0;\n\n      if (!users.length) {\n        return {\n          content: [{\n            type: \"text\",\n            text: `No users found matching '${params.query}'`\n          }]\n        };\n      }\n\n      // Prepare structured output\n      const output = {\n        total,\n        count: users.length,\n        offset: params.offset,\n        users: users.map((user: any) => ({\n          id: user.id,\n          name: user.name,\n          email: user.email,\n          ...(user.team ? { team: user.team } : {}),\n          active: user.active ?? true\n        })),\n        has_more: total > params.offset + users.length,\n        ...(total > params.offset + users.length ? {\n          next_offset: params.offset + users.length\n        } : {})\n      };\n\n      // Format text representation based on requested format\n      let textContent: string;\n      if (params.response_format === ResponseFormat.MARKDOWN) {\n        const lines = [`# User Search Results: '${params.query}'`, \"\",\n          `Found ${total} users (showing ${users.length})`, \"\"];\n        for (const user of users) {\n          lines.push(`## ${user.name} (${user.id})`);\n          lines.push(`- **Email**: ${user.email}`);\n          if (user.team) lines.push(`- **Team**: ${user.team}`);\n          lines.push(\"\");\n        }\n        textContent = lines.join(\"\\n\");\n      } else {\n        textContent = JSON.stringify(output, null, 2);\n      }\n\n      return {\n        content: [{ type: \"text\", text: textContent }],\n        structuredContent: output // Modern pattern for structured data\n      };\n    } catch (error) {\n      return {\n        content: [{\n          type: \"text\",\n          text: handleApiError(error)\n        }]\n      };\n    }\n  }\n);\n```\n\n## Zod Schemas for Input Validation\n\nZod provides runtime type validation:\n\n```typescript\nimport { z } from \"zod\";\n\n// Basic schema with validation\nconst CreateUserSchema = z.object({\n  name: z.string()\n    .min(1, \"Name is required\")\n    .max(100, \"Name must not exceed 100 characters\"),\n  email: z.string()\n    .email(\"Invalid email format\"),\n  age: z.number()\n    .int(\"Age must be a whole number\")\n    .min(0, \"Age cannot be negative\")\n    .max(150, \"Age cannot be greater than 150\")\n}).strict();  // Use .strict() to forbid extra fields\n\n// Enums\nenum ResponseFormat {\n  MARKDOWN = \"markdown\",\n  JSON = \"json\"\n}\n\nconst SearchSchema = z.object({\n  response_format: z.nativeEnum(ResponseFormat)\n    .default(ResponseFormat.MARKDOWN)\n    .describe(\"Output format\")\n});\n\n// Optional fields with defaults\nconst PaginationSchema = z.object({\n  limit: z.number()\n    .int()\n    .min(1)\n    .max(100)\n    .default(20)\n    .describe(\"Maximum results to return\"),\n  offset: z.number()\n    .int()\n    .min(0)\n    .default(0)\n    .describe(\"Number of results to skip\")\n});\n```\n\n## Response Format Options\n\nSupport multiple output formats for flexibility:\n\n```typescript\nenum ResponseFormat {\n  MARKDOWN = \"markdown\",\n  JSON = \"json\"\n}\n\nconst inputSchema = z.object({\n  query: z.string(),\n  response_format: z.nativeEnum(ResponseFormat)\n    .default(ResponseFormat.MARKDOWN)\n    .describe(\"Output format: 'markdown' for human-readable or 'json' for machine-readable\")\n});\n```\n\n**Markdown format**:\n- Use headers, lists, and formatting for clarity\n- Convert timestamps to human-readable format\n- Show display names with IDs in parentheses\n- Omit verbose metadata\n- Group related information logically\n\n**JSON format**:\n- Return complete, structured data suitable for programmatic processing\n- Include all available fields and metadata\n- Use consistent field names and types\n\n## Pagination Implementation\n\nFor tools that list resources:\n\n```typescript\nconst ListSchema = z.object({\n  limit: z.number().int().min(1).max(100).default(20),\n  offset: z.number().int().min(0).default(0)\n});\n\nasync function listItems(params: z.infer<typeof ListSchema>) {\n  const data = await apiRequest(params.limit, params.offset);\n\n  const response = {\n    total: data.total,\n    count: data.items.length,\n    offset: params.offset,\n    items: data.items,\n    has_more: data.total > params.offset + data.items.length,\n    next_offset: data.total > params.offset + data.items.length\n      ? params.offset + data.items.length\n      : undefined\n  };\n\n  return JSON.stringify(response, null, 2);\n}\n```\n\n## Character Limits and Truncation\n\nAdd a CHARACTER_LIMIT constant to prevent overwhelming responses:\n\n```typescript\n// At module level in constants.ts\nexport const CHARACTER_LIMIT = 25000;  // Maximum response size in characters\n\nasync function searchTool(params: SearchInput) {\n  let result = generateResponse(data);\n\n  // Check character limit and truncate if needed\n  if (result.length > CHARACTER_LIMIT) {\n    const truncatedData = data.slice(0, Math.max(1, data.length / 2));\n    response.data = truncatedData;\n    response.truncated = true;\n    response.truncation_message =\n      `Response truncated from ${data.length} to ${truncatedData.length} items. ` +\n      `Use 'offset' parameter or add filters to see more results.`;\n    result = JSON.stringify(response, null, 2);\n  }\n\n  return result;\n}\n```\n\n## Error Handling\n\nProvide clear, actionable error messages:\n\n```typescript\nimport axios, { AxiosError } from \"axios\";\n\nfunction handleApiError(error: unknown): string {\n  if (error instanceof AxiosError) {\n    if (error.response) {\n      switch (error.response.status) {\n        case 404:\n          return \"Error: Resource not found. Please check the ID is correct.\";\n        case 403:\n          return \"Error: Permission denied. You don't have access to this resource.\";\n        case 429:\n          return \"Error: Rate limit exceeded. Please wait before making more requests.\";\n        default:\n          return `Error: API request failed with status ${error.response.status}`;\n      }\n    } else if (error.code === \"ECONNABORTED\") {\n      return \"Error: Request timed out. Please try again.\";\n    }\n  }\n  return `Error: Unexpected error occurred: ${error instanceof Error ? error.message : String(error)}`;\n}\n```\n\n## Shared Utilities\n\nExtract common functionality into reusable functions:\n\n```typescript\n// Shared API request function\nasync function makeApiRequest<T>(\n  endpoint: string,\n  method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" = \"GET\",\n  data?: any,\n  params?: any\n): Promise<T> {\n  try {\n    const response = await axios({\n      method,\n      url: `${API_BASE_URL}/${endpoint}`,\n      data,\n      params,\n      timeout: 30000,\n      headers: {\n        \"Content-Type\": \"application/json\",\n        \"Accept\": \"application/json\"\n      }\n    });\n    return response.data;\n  } catch (error) {\n    throw error;\n  }\n}\n```\n\n## Async/Await Best Practices\n\nAlways use async/await for network requests and I/O operations:\n\n```typescript\n// Good: Async network request\nasync function fetchData(resourceId: string): Promise<ResourceData> {\n  const response = await axios.get(`${API_URL}/resource/${resourceId}`);\n  return response.data;\n}\n\n// Bad: Promise chains\nfunction fetchData(resourceId: string): Promise<ResourceData> {\n  return axios.get(`${API_URL}/resource/${resourceId}`)\n    .then(response => response.data);  // Harder to read and maintain\n}\n```\n\n## TypeScript Best Practices\n\n1. **Use Strict TypeScript**: Enable strict mode in tsconfig.json\n2. **Define Interfaces**: Create clear interface definitions for all data structures\n3. **Avoid `any`**: Use proper types or `unknown` instead of `any`\n4. **Zod for Runtime Validation**: Use Zod schemas to validate external data\n5. **Type Guards**: Create type guard functions for complex type checking\n6. **Error Handling**: Always use try-catch with proper error type checking\n7. **Null Safety**: Use optional chaining (`?.`) and nullish coalescing (`??`)\n\n```typescript\n// Good: Type-safe with Zod and interfaces\ninterface UserResponse {\n  id: string;\n  name: string;\n  email: string;\n  team?: string;\n  active: boolean;\n}\n\nconst UserSchema = z.object({\n  id: z.string(),\n  name: z.string(),\n  email: z.string().email(),\n  team: z.string().optional(),\n  active: z.boolean()\n});\n\ntype User = z.infer<typeof UserSchema>;\n\nasync function getUser(id: string): Promise<User> {\n  const data = await apiCall(`/users/${id}`);\n  return UserSchema.parse(data);  // Runtime validation\n}\n\n// Bad: Using any\nasync function getUser(id: string): Promise<any> {\n  return await apiCall(`/users/${id}`);  // No type safety\n}\n```\n\n## Package Configuration\n\n### package.json\n\n```json\n{\n  \"name\": \"{service}-mcp-server\",\n  \"version\": \"1.0.0\",\n  \"description\": \"MCP server for {Service} API integration\",\n  \"type\": \"module\",\n  \"main\": \"dist/index.js\",\n  \"scripts\": {\n    \"start\": \"node dist/index.js\",\n    \"dev\": \"tsx watch src/index.ts\",\n    \"build\": \"tsc\",\n    \"clean\": \"rm -rf dist\"\n  },\n  \"engines\": {\n    \"node\": \">=18\"\n  },\n  \"dependencies\": {\n    \"@modelcontextprotocol/sdk\": \"^1.6.1\",\n    \"axios\": \"^1.7.9\",\n    \"zod\": \"^3.23.8\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.10.0\",\n    \"tsx\": \"^4.19.2\",\n    \"typescript\": \"^5.7.2\"\n  }\n}\n```\n\n### tsconfig.json\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"Node16\",\n    \"moduleResolution\": \"Node16\",\n    \"lib\": [\"ES2022\"],\n    \"outDir\": \"./dist\",\n    \"rootDir\": \"./src\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"declaration\": true,\n    \"declarationMap\": true,\n    \"sourceMap\": true,\n    \"allowSyntheticDefaultImports\": true\n  },\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"node_modules\", \"dist\"]\n}\n```\n\n## Complete Example\n\n```typescript\n#!/usr/bin/env node\n/**\n * MCP Server for Example Service.\n *\n * This server provides tools to interact with Example API, including user search,\n * project management, and data export capabilities.\n */\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport axios, { AxiosError } from \"axios\";\n\n// Constants\nconst API_BASE_URL = \"https://api.example.com/v1\";\nconst CHARACTER_LIMIT = 25000;\n\n// Enums\nenum ResponseFormat {\n  MARKDOWN = \"markdown\",\n  JSON = \"json\"\n}\n\n// Zod schemas\nconst UserSearchInputSchema = z.object({\n  query: z.string()\n    .min(2, \"Query must be at least 2 characters\")\n    .max(200, \"Query must not exceed 200 characters\")\n    .describe(\"Search string to match against names/emails\"),\n  limit: z.number()\n    .int()\n    .min(1)\n    .max(100)\n    .default(20)\n    .describe(\"Maximum results to return\"),\n  offset: z.number()\n    .int()\n    .min(0)\n    .default(0)\n    .describe(\"Number of results to skip for pagination\"),\n  response_format: z.nativeEnum(ResponseFormat)\n    .default(ResponseFormat.MARKDOWN)\n    .describe(\"Output format: 'markdown' for human-readable or 'json' for machine-readable\")\n}).strict();\n\ntype UserSearchInput = z.infer<typeof UserSearchInputSchema>;\n\n// Shared utility functions\nasync function makeApiRequest<T>(\n  endpoint: string,\n  method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" = \"GET\",\n  data?: any,\n  params?: any\n): Promise<T> {\n  try {\n    const response = await axios({\n      method,\n      url: `${API_BASE_URL}/${endpoint}`,\n      data,\n      params,\n      timeout: 30000,\n      headers: {\n        \"Content-Type\": \"application/json\",\n        \"Accept\": \"application/json\"\n      }\n    });\n    return response.data;\n  } catch (error) {\n    throw error;\n  }\n}\n\nfunction handleApiError(error: unknown): string {\n  if (error instanceof AxiosError) {\n    if (error.response) {\n      switch (error.response.status) {\n        case 404:\n          return \"Error: Resource not found. Please check the ID is correct.\";\n        case 403:\n          return \"Error: Permission denied. You don't have access to this resource.\";\n        case 429:\n          return \"Error: Rate limit exceeded. Please wait before making more requests.\";\n        default:\n          return `Error: API request failed with status ${error.response.status}`;\n      }\n    } else if (error.code === \"ECONNABORTED\") {\n      return \"Error: Request timed out. Please try again.\";\n    }\n  }\n  return `Error: Unexpected error occurred: ${error instanceof Error ? error.message : String(error)}`;\n}\n\n// Create MCP server instance\nconst server = new McpServer({\n  name: \"example-mcp\",\n  version: \"1.0.0\"\n});\n\n// Register tools\nserver.registerTool(\n  \"example_search_users\",\n  {\n    title: \"Search Example Users\",\n    description: `[Full description as shown above]`,\n    inputSchema: UserSearchInputSchema,\n    annotations: {\n      readOnlyHint: true,\n      destructiveHint: false,\n      idempotentHint: true,\n      openWorldHint: true\n    }\n  },\n  async (params: UserSearchInput) => {\n    // Implementation as shown above\n  }\n);\n\n// Main function\n// For stdio (local):\nasync function runStdio() {\n  if (!process.env.EXAMPLE_API_KEY) {\n    console.error(\"ERROR: EXAMPLE_API_KEY environment variable is required\");\n    process.exit(1);\n  }\n\n  const transport = new StdioServerTransport();\n  await server.connect(transport);\n  console.error(\"MCP server running via stdio\");\n}\n\n// For streamable HTTP (remote):\nasync function runHTTP() {\n  if (!process.env.EXAMPLE_API_KEY) {\n    console.error(\"ERROR: EXAMPLE_API_KEY environment variable is required\");\n    process.exit(1);\n  }\n\n  const app = express();\n  app.use(express.json());\n\n  app.post('/mcp', async (req, res) => {\n    const transport = new StreamableHTTPServerTransport({\n      sessionIdGenerator: undefined,\n      enableJsonResponse: true\n    });\n    res.on('close', () => transport.close());\n    await server.connect(transport);\n    await transport.handleRequest(req, res, req.body);\n  });\n\n  const port = parseInt(process.env.PORT || '3000');\n  app.listen(port, () => {\n    console.error(`MCP server running on http://localhost:${port}/mcp`);\n  });\n}\n\n// Choose transport based on environment\nconst transport = process.env.TRANSPORT || 'stdio';\nif (transport === 'http') {\n  runHTTP().catch(error => {\n    console.error(\"Server error:\", error);\n    process.exit(1);\n  });\n} else {\n  runStdio().catch(error => {\n    console.error(\"Server error:\", error);\n    process.exit(1);\n  });\n}\n```\n\n---\n\n## Advanced MCP Features\n\n### Resource Registration\n\nExpose data as resources for efficient, URI-based access:\n\n```typescript\nimport { ResourceTemplate } from \"@modelcontextprotocol/sdk/types.js\";\n\n// Register a resource with URI template\nserver.registerResource(\n  {\n    uri: \"file://documents/{name}\",\n    name: \"Document Resource\",\n    description: \"Access documents by name\",\n    mimeType: \"text/plain\"\n  },\n  async (uri: string) => {\n    // Extract parameter from URI\n    const match = uri.match(/^file:\\/\\/documents\\/(.+)$/);\n    if (!match) {\n      throw new Error(\"Invalid URI format\");\n    }\n\n    const documentName = match[1];\n    const content = await loadDocument(documentName);\n\n    return {\n      contents: [{\n        uri,\n        mimeType: \"text/plain\",\n        text: content\n      }]\n    };\n  }\n);\n\n// List available resources dynamically\nserver.registerResourceList(async () => {\n  const documents = await getAvailableDocuments();\n  return {\n    resources: documents.map(doc => ({\n      uri: `file://documents/${doc.name}`,\n      name: doc.name,\n      mimeType: \"text/plain\",\n      description: doc.description\n    }))\n  };\n});\n```\n\n**When to use Resources vs Tools:**\n- **Resources**: For data access with simple URI-based parameters\n- **Tools**: For complex operations requiring validation and business logic\n- **Resources**: When data is relatively static or template-based\n- **Tools**: When operations have side effects or complex workflows\n\n### Transport Options\n\nThe TypeScript SDK supports two main transport mechanisms:\n\n#### Streamable HTTP (Recommended for Remote Servers)\n\n```typescript\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport express from \"express\";\n\nconst app = express();\napp.use(express.json());\n\napp.post('/mcp', async (req, res) => {\n  // Create new transport for each request (stateless, prevents request ID collisions)\n  const transport = new StreamableHTTPServerTransport({\n    sessionIdGenerator: undefined,\n    enableJsonResponse: true\n  });\n\n  res.on('close', () => transport.close());\n\n  await server.connect(transport);\n  await transport.handleRequest(req, res, req.body);\n});\n\napp.listen(3000);\n```\n\n#### stdio (For Local Integrations)\n\n```typescript\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n```\n\n**Transport selection:**\n- **Streamable HTTP**: Web services, remote access, multiple clients\n- **stdio**: Command-line tools, local development, subprocess integration\n\n### Notification Support\n\nNotify clients when server state changes:\n\n```typescript\n// Notify when tools list changes\nserver.notification({\n  method: \"notifications/tools/list_changed\"\n});\n\n// Notify when resources change\nserver.notification({\n  method: \"notifications/resources/list_changed\"\n});\n```\n\nUse notifications sparingly - only when server capabilities genuinely change.\n\n---\n\n## Code Best Practices\n\n### Code Composability and Reusability\n\nYour implementation MUST prioritize composability and code reuse:\n\n1. **Extract Common Functionality**:\n   - Create reusable helper functions for operations used across multiple tools\n   - Build shared API clients for HTTP requests instead of duplicating code\n   - Centralize error handling logic in utility functions\n   - Extract business logic into dedicated functions that can be composed\n   - Extract shared markdown or JSON field selection & formatting functionality\n\n2. **Avoid Duplication**:\n   - NEVER copy-paste similar code between tools\n   - If you find yourself writing similar logic twice, extract it into a function\n   - Common operations like pagination, filtering, field selection, and formatting should be shared\n   - Authentication/authorization logic should be centralized\n\n## Building and Running\n\nAlways build your TypeScript code before running:\n\n```bash\n# Build the project\nnpm run build\n\n# Run the server\nnpm start\n\n# Development with auto-reload\nnpm run dev\n```\n\nAlways ensure `npm run build` completes successfully before considering the implementation complete.\n\n## Quality Checklist\n\nBefore finalizing your Node/TypeScript MCP server implementation, ensure:\n\n### Strategic Design\n- [ ] Tools enable complete workflows, not just API endpoint wrappers\n- [ ] Tool names reflect natural task subdivisions\n- [ ] Response formats optimize for agent context efficiency\n- [ ] Human-readable identifiers used where appropriate\n- [ ] Error messages guide agents toward correct usage\n\n### Implementation Quality\n- [ ] FOCUSED IMPLEMENTATION: Most important and valuable tools implemented\n- [ ] All tools registered using `registerTool` with complete configuration\n- [ ] All tools include `title`, `description`, `inputSchema`, and `annotations`\n- [ ] Annotations correctly set (readOnlyHint, destructiveHint, idempotentHint, openWorldHint)\n- [ ] All tools use Zod schemas for runtime input validation with `.strict()` enforcement\n- [ ] All Zod schemas have proper constraints and descriptive error messages\n- [ ] All tools have comprehensive descriptions with explicit input/output types\n- [ ] Descriptions include return value examples and complete schema documentation\n- [ ] Error messages are clear, actionable, and educational\n\n### TypeScript Quality\n- [ ] TypeScript interfaces are defined for all data structures\n- [ ] Strict TypeScript is enabled in tsconfig.json\n- [ ] No use of `any` type - use `unknown` or proper types instead\n- [ ] All async functions have explicit Promise<T> return types\n- [ ] Error handling uses proper type guards (e.g., `axios.isAxiosError`, `z.ZodError`)\n\n### Advanced Features (where applicable)\n- [ ] Resources registered for appropriate data endpoints\n- [ ] Appropriate transport configured (stdio or streamable HTTP)\n- [ ] Notifications implemented for dynamic server capabilities\n- [ ] Type-safe with SDK interfaces\n\n### Project Configuration\n- [ ] Package.json includes all necessary dependencies\n- [ ] Build script produces working JavaScript in dist/ directory\n- [ ] Main entry point is properly configured as dist/index.js\n- [ ] Server name follows format: `{service}-mcp-server`\n- [ ] tsconfig.json properly configured with strict mode\n\n### Code Quality\n- [ ] Pagination is properly implemented where applicable\n- [ ] Large responses check CHARACTER_LIMIT constant and truncate with clear messages\n- [ ] Filtering options are provided for potentially large result sets\n- [ ] All network operations handle timeouts and connection errors gracefully\n- [ ] Common functionality is extracted into reusable functions\n- [ ] Return types are consistent across similar operations\n\n### Testing and Build\n- [ ] `npm run build` completes successfully without errors\n- [ ] dist/index.js created and executable\n- [ ] Server runs: `node dist/index.js --help`\n- [ ] All imports resolve correctly\n- [ ] Sample tool calls work as expected\n","core/skills/builtin/mcp-builder/reference/python_mcp_server.md":"# Python MCP Server Implementation Guide\n\n## Overview\n\nThis document provides Python-specific best practices and examples for implementing MCP servers using the MCP Python SDK. It covers server setup, tool registration patterns, input validation with Pydantic, error handling, and complete working examples.\n\n---\n\n## Quick Reference\n\n### Key Imports\n```python\nfrom mcp.server.fastmcp import FastMCP\nfrom pydantic import BaseModel, Field, field_validator, ConfigDict\nfrom typing import Optional, List, Dict, Any\nfrom enum import Enum\nimport httpx\n```\n\n### Server Initialization\n```python\nmcp = FastMCP(\"service_mcp\")\n```\n\n### Tool Registration Pattern\n```python\n@mcp.tool(name=\"tool_name\", annotations={...})\nasync def tool_function(params: InputModel) -> str:\n    # Implementation\n    pass\n```\n\n---\n\n## MCP Python SDK and FastMCP\n\nThe official MCP Python SDK provides FastMCP, a high-level framework for building MCP servers. It provides:\n- Automatic description and inputSchema generation from function signatures and docstrings\n- Pydantic model integration for input validation\n- Decorator-based tool registration with `@mcp.tool`\n\n**For complete SDK documentation, use WebFetch to load:**\n`https://raw.githubusercontent.com/modelcontextprotocol/python-sdk/main/README.md`\n\n## Server Naming Convention\n\nPython MCP servers must follow this naming pattern:\n- **Format**: `{service}_mcp` (lowercase with underscores)\n- **Examples**: `github_mcp`, `jira_mcp`, `stripe_mcp`\n\nThe name should be:\n- General (not tied to specific features)\n- Descriptive of the service/API being integrated\n- Easy to infer from the task description\n- Without version numbers or dates\n\n## Tool Implementation\n\n### Tool Naming\n\nUse snake_case for tool names (e.g., \"search_users\", \"create_project\", \"get_channel_info\") with clear, action-oriented names.\n\n**Avoid Naming Conflicts**: Include the service context to prevent overlaps:\n- Use \"slack_send_message\" instead of just \"send_message\"\n- Use \"github_create_issue\" instead of just \"create_issue\"\n- Use \"asana_list_tasks\" instead of just \"list_tasks\"\n\n### Tool Structure with FastMCP\n\nTools are defined using the `@mcp.tool` decorator with Pydantic models for input validation:\n\n```python\nfrom pydantic import BaseModel, Field, ConfigDict\nfrom mcp.server.fastmcp import FastMCP\n\n# Initialize the MCP server\nmcp = FastMCP(\"example_mcp\")\n\n# Define Pydantic model for input validation\nclass ServiceToolInput(BaseModel):\n    '''Input model for service tool operation.'''\n    model_config = ConfigDict(\n        str_strip_whitespace=True,  # Auto-strip whitespace from strings\n        validate_assignment=True,    # Validate on assignment\n        extra='forbid'              # Forbid extra fields\n    )\n\n    param1: str = Field(..., description=\"First parameter description (e.g., 'user123', 'project-abc')\", min_length=1, max_length=100)\n    param2: Optional[int] = Field(default=None, description=\"Optional integer parameter with constraints\", ge=0, le=1000)\n    tags: Optional[List[str]] = Field(default_factory=list, description=\"List of tags to apply\", max_items=10)\n\n@mcp.tool(\n    name=\"service_tool_name\",\n    annotations={\n        \"title\": \"Human-Readable Tool Title\",\n        \"readOnlyHint\": True,     # Tool does not modify environment\n        \"destructiveHint\": False,  # Tool does not perform destructive operations\n        \"idempotentHint\": True,    # Repeated calls have no additional effect\n        \"openWorldHint\": False     # Tool does not interact with external entities\n    }\n)\nasync def service_tool_name(params: ServiceToolInput) -> str:\n    '''Tool description automatically becomes the 'description' field.\n\n    This tool performs a specific operation on the service. It validates all inputs\n    using the ServiceToolInput Pydantic model before processing.\n\n    Args:\n        params (ServiceToolInput): Validated input parameters containing:\n            - param1 (str): First parameter description\n            - param2 (Optional[int]): Optional parameter with default\n            - tags (Optional[List[str]]): List of tags\n\n    Returns:\n        str: JSON-formatted response containing operation results\n    '''\n    # Implementation here\n    pass\n```\n\n## Pydantic v2 Key Features\n\n- Use `model_config` instead of nested `Config` class\n- Use `field_validator` instead of deprecated `validator`\n- Use `model_dump()` instead of deprecated `dict()`\n- Validators require `@classmethod` decorator\n- Type hints are required for validator methods\n\n```python\nfrom pydantic import BaseModel, Field, field_validator, ConfigDict\n\nclass CreateUserInput(BaseModel):\n    model_config = ConfigDict(\n        str_strip_whitespace=True,\n        validate_assignment=True\n    )\n\n    name: str = Field(..., description=\"User's full name\", min_length=1, max_length=100)\n    email: str = Field(..., description=\"User's email address\", pattern=r'^[\\w\\.-]+@[\\w\\.-]+\\.\\w+$')\n    age: int = Field(..., description=\"User's age\", ge=0, le=150)\n\n    @field_validator('email')\n    @classmethod\n    def validate_email(cls, v: str) -> str:\n        if not v.strip():\n            raise ValueError(\"Email cannot be empty\")\n        return v.lower()\n```\n\n## Response Format Options\n\nSupport multiple output formats for flexibility:\n\n```python\nfrom enum import Enum\n\nclass ResponseFormat(str, Enum):\n    '''Output format for tool responses.'''\n    MARKDOWN = \"markdown\"\n    JSON = \"json\"\n\nclass UserSearchInput(BaseModel):\n    query: str = Field(..., description=\"Search query\")\n    response_format: ResponseFormat = Field(\n        default=ResponseFormat.MARKDOWN,\n        description=\"Output format: 'markdown' for human-readable or 'json' for machine-readable\"\n    )\n```\n\n**Markdown format**:\n- Use headers, lists, and formatting for clarity\n- Convert timestamps to human-readable format (e.g., \"2024-01-15 10:30:00 UTC\" instead of epoch)\n- Show display names with IDs in parentheses (e.g., \"@john.doe (U123456)\")\n- Omit verbose metadata (e.g., show only one profile image URL, not all sizes)\n- Group related information logically\n\n**JSON format**:\n- Return complete, structured data suitable for programmatic processing\n- Include all available fields and metadata\n- Use consistent field names and types\n\n## Pagination Implementation\n\nFor tools that list resources:\n\n```python\nclass ListInput(BaseModel):\n    limit: Optional[int] = Field(default=20, description=\"Maximum results to return\", ge=1, le=100)\n    offset: Optional[int] = Field(default=0, description=\"Number of results to skip for pagination\", ge=0)\n\nasync def list_items(params: ListInput) -> str:\n    # Make API request with pagination\n    data = await api_request(limit=params.limit, offset=params.offset)\n\n    # Return pagination info\n    response = {\n        \"total\": data[\"total\"],\n        \"count\": len(data[\"items\"]),\n        \"offset\": params.offset,\n        \"items\": data[\"items\"],\n        \"has_more\": data[\"total\"] > params.offset + len(data[\"items\"]),\n        \"next_offset\": params.offset + len(data[\"items\"]) if data[\"total\"] > params.offset + len(data[\"items\"]) else None\n    }\n    return json.dumps(response, indent=2)\n```\n\n## Error Handling\n\nProvide clear, actionable error messages:\n\n```python\ndef _handle_api_error(e: Exception) -> str:\n    '''Consistent error formatting across all tools.'''\n    if isinstance(e, httpx.HTTPStatusError):\n        if e.response.status_code == 404:\n            return \"Error: Resource not found. Please check the ID is correct.\"\n        elif e.response.status_code == 403:\n            return \"Error: Permission denied. You don't have access to this resource.\"\n        elif e.response.status_code == 429:\n            return \"Error: Rate limit exceeded. Please wait before making more requests.\"\n        return f\"Error: API request failed with status {e.response.status_code}\"\n    elif isinstance(e, httpx.TimeoutException):\n        return \"Error: Request timed out. Please try again.\"\n    return f\"Error: Unexpected error occurred: {type(e).__name__}\"\n```\n\n## Shared Utilities\n\nExtract common functionality into reusable functions:\n\n```python\n# Shared API request function\nasync def _make_api_request(endpoint: str, method: str = \"GET\", **kwargs) -> dict:\n    '''Reusable function for all API calls.'''\n    async with httpx.AsyncClient() as client:\n        response = await client.request(\n            method,\n            f\"{API_BASE_URL}/{endpoint}\",\n            timeout=30.0,\n            **kwargs\n        )\n        response.raise_for_status()\n        return response.json()\n```\n\n## Async/Await Best Practices\n\nAlways use async/await for network requests and I/O operations:\n\n```python\n# Good: Async network request\nasync def fetch_data(resource_id: str) -> dict:\n    async with httpx.AsyncClient() as client:\n        response = await client.get(f\"{API_URL}/resource/{resource_id}\")\n        response.raise_for_status()\n        return response.json()\n\n# Bad: Synchronous request\ndef fetch_data(resource_id: str) -> dict:\n    response = requests.get(f\"{API_URL}/resource/{resource_id}\")  # Blocks\n    return response.json()\n```\n\n## Type Hints\n\nUse type hints throughout:\n\n```python\nfrom typing import Optional, List, Dict, Any\n\nasync def get_user(user_id: str) -> Dict[str, Any]:\n    data = await fetch_user(user_id)\n    return {\"id\": data[\"id\"], \"name\": data[\"name\"]}\n```\n\n## Tool Docstrings\n\nEvery tool must have comprehensive docstrings with explicit type information:\n\n```python\nasync def search_users(params: UserSearchInput) -> str:\n    '''\n    Search for users in the Example system by name, email, or team.\n\n    This tool searches across all user profiles in the Example platform,\n    supporting partial matches and various search filters. It does NOT\n    create or modify users, only searches existing ones.\n\n    Args:\n        params (UserSearchInput): Validated input parameters containing:\n            - query (str): Search string to match against names/emails (e.g., \"john\", \"@example.com\", \"team:marketing\")\n            - limit (Optional[int]): Maximum results to return, between 1-100 (default: 20)\n            - offset (Optional[int]): Number of results to skip for pagination (default: 0)\n\n    Returns:\n        str: JSON-formatted string containing search results with the following schema:\n\n        Success response:\n        {\n            \"total\": int,           # Total number of matches found\n            \"count\": int,           # Number of results in this response\n            \"offset\": int,          # Current pagination offset\n            \"users\": [\n                {\n                    \"id\": str,      # User ID (e.g., \"U123456789\")\n                    \"name\": str,    # Full name (e.g., \"John Doe\")\n                    \"email\": str,   # Email address (e.g., \"john@example.com\")\n                    \"team\": str     # Team name (e.g., \"Marketing\") - optional\n                }\n            ]\n        }\n\n        Error response:\n        \"Error: <error message>\" or \"No users found matching '<query>'\"\n\n    Examples:\n        - Use when: \"Find all marketing team members\" -> params with query=\"team:marketing\"\n        - Use when: \"Search for John's account\" -> params with query=\"john\"\n        - Don't use when: You need to create a user (use example_create_user instead)\n        - Don't use when: You have a user ID and need full details (use example_get_user instead)\n\n    Error Handling:\n        - Input validation errors are handled by Pydantic model\n        - Returns \"Error: Rate limit exceeded\" if too many requests (429 status)\n        - Returns \"Error: Invalid API authentication\" if API key is invalid (401 status)\n        - Returns formatted list of results or \"No users found matching 'query'\"\n    '''\n```\n\n## Complete Example\n\nSee below for a complete Python MCP server example:\n\n```python\n#!/usr/bin/env python3\n'''\nMCP Server for Example Service.\n\nThis server provides tools to interact with Example API, including user search,\nproject management, and data export capabilities.\n'''\n\nfrom typing import Optional, List, Dict, Any\nfrom enum import Enum\nimport httpx\nfrom pydantic import BaseModel, Field, field_validator, ConfigDict\nfrom mcp.server.fastmcp import FastMCP\n\n# Initialize the MCP server\nmcp = FastMCP(\"example_mcp\")\n\n# Constants\nAPI_BASE_URL = \"https://api.example.com/v1\"\n\n# Enums\nclass ResponseFormat(str, Enum):\n    '''Output format for tool responses.'''\n    MARKDOWN = \"markdown\"\n    JSON = \"json\"\n\n# Pydantic Models for Input Validation\nclass UserSearchInput(BaseModel):\n    '''Input model for user search operations.'''\n    model_config = ConfigDict(\n        str_strip_whitespace=True,\n        validate_assignment=True\n    )\n\n    query: str = Field(..., description=\"Search string to match against names/emails\", min_length=2, max_length=200)\n    limit: Optional[int] = Field(default=20, description=\"Maximum results to return\", ge=1, le=100)\n    offset: Optional[int] = Field(default=0, description=\"Number of results to skip for pagination\", ge=0)\n    response_format: ResponseFormat = Field(default=ResponseFormat.MARKDOWN, description=\"Output format\")\n\n    @field_validator('query')\n    @classmethod\n    def validate_query(cls, v: str) -> str:\n        if not v.strip():\n            raise ValueError(\"Query cannot be empty or whitespace only\")\n        return v.strip()\n\n# Shared utility functions\nasync def _make_api_request(endpoint: str, method: str = \"GET\", **kwargs) -> dict:\n    '''Reusable function for all API calls.'''\n    async with httpx.AsyncClient() as client:\n        response = await client.request(\n            method,\n            f\"{API_BASE_URL}/{endpoint}\",\n            timeout=30.0,\n            **kwargs\n        )\n        response.raise_for_status()\n        return response.json()\n\ndef _handle_api_error(e: Exception) -> str:\n    '''Consistent error formatting across all tools.'''\n    if isinstance(e, httpx.HTTPStatusError):\n        if e.response.status_code == 404:\n            return \"Error: Resource not found. Please check the ID is correct.\"\n        elif e.response.status_code == 403:\n            return \"Error: Permission denied. You don't have access to this resource.\"\n        elif e.response.status_code == 429:\n            return \"Error: Rate limit exceeded. Please wait before making more requests.\"\n        return f\"Error: API request failed with status {e.response.status_code}\"\n    elif isinstance(e, httpx.TimeoutException):\n        return \"Error: Request timed out. Please try again.\"\n    return f\"Error: Unexpected error occurred: {type(e).__name__}\"\n\n# Tool definitions\n@mcp.tool(\n    name=\"example_search_users\",\n    annotations={\n        \"title\": \"Search Example Users\",\n        \"readOnlyHint\": True,\n        \"destructiveHint\": False,\n        \"idempotentHint\": True,\n        \"openWorldHint\": True\n    }\n)\nasync def example_search_users(params: UserSearchInput) -> str:\n    '''Search for users in the Example system by name, email, or team.\n\n    [Full docstring as shown above]\n    '''\n    try:\n        # Make API request using validated parameters\n        data = await _make_api_request(\n            \"users/search\",\n            params={\n                \"q\": params.query,\n                \"limit\": params.limit,\n                \"offset\": params.offset\n            }\n        )\n\n        users = data.get(\"users\", [])\n        total = data.get(\"total\", 0)\n\n        if not users:\n            return f\"No users found matching '{params.query}'\"\n\n        # Format response based on requested format\n        if params.response_format == ResponseFormat.MARKDOWN:\n            lines = [f\"# User Search Results: '{params.query}'\", \"\"]\n            lines.append(f\"Found {total} users (showing {len(users)})\")\n            lines.append(\"\")\n\n            for user in users:\n                lines.append(f\"## {user['name']} ({user['id']})\")\n                lines.append(f\"- **Email**: {user['email']}\")\n                if user.get('team'):\n                    lines.append(f\"- **Team**: {user['team']}\")\n                lines.append(\"\")\n\n            return \"\\n\".join(lines)\n\n        else:\n            # Machine-readable JSON format\n            import json\n            response = {\n                \"total\": total,\n                \"count\": len(users),\n                \"offset\": params.offset,\n                \"users\": users\n            }\n            return json.dumps(response, indent=2)\n\n    except Exception as e:\n        return _handle_api_error(e)\n\nif __name__ == \"__main__\":\n    mcp.run()\n```\n\n---\n\n## Advanced FastMCP Features\n\n### Context Parameter Injection\n\nFastMCP can automatically inject a `Context` parameter into tools for advanced capabilities like logging, progress reporting, resource reading, and user interaction:\n\n```python\nfrom mcp.server.fastmcp import FastMCP, Context\n\nmcp = FastMCP(\"example_mcp\")\n\n@mcp.tool()\nasync def advanced_search(query: str, ctx: Context) -> str:\n    '''Advanced tool with context access for logging and progress.'''\n\n    # Report progress for long operations\n    await ctx.report_progress(0.25, \"Starting search...\")\n\n    # Log information for debugging\n    await ctx.log_info(\"Processing query\", {\"query\": query, \"timestamp\": datetime.now()})\n\n    # Perform search\n    results = await search_api(query)\n    await ctx.report_progress(0.75, \"Formatting results...\")\n\n    # Access server configuration\n    server_name = ctx.fastmcp.name\n\n    return format_results(results)\n\n@mcp.tool()\nasync def interactive_tool(resource_id: str, ctx: Context) -> str:\n    '''Tool that can request additional input from users.'''\n\n    # Request sensitive information when needed\n    api_key = await ctx.elicit(\n        prompt=\"Please provide your API key:\",\n        input_type=\"password\"\n    )\n\n    # Use the provided key\n    return await api_call(resource_id, api_key)\n```\n\n**Context capabilities:**\n- `ctx.report_progress(progress, message)` - Report progress for long operations\n- `ctx.log_info(message, data)` / `ctx.log_error()` / `ctx.log_debug()` - Logging\n- `ctx.elicit(prompt, input_type)` - Request input from users\n- `ctx.fastmcp.name` - Access server configuration\n- `ctx.read_resource(uri)` - Read MCP resources\n\n### Resource Registration\n\nExpose data as resources for efficient, template-based access:\n\n```python\n@mcp.resource(\"file://documents/{name}\")\nasync def get_document(name: str) -> str:\n    '''Expose documents as MCP resources.\n\n    Resources are useful for static or semi-static data that doesn't\n    require complex parameters. They use URI templates for flexible access.\n    '''\n    document_path = f\"./docs/{name}\"\n    with open(document_path, \"r\") as f:\n        return f.read()\n\n@mcp.resource(\"config://settings/{key}\")\nasync def get_setting(key: str, ctx: Context) -> str:\n    '''Expose configuration as resources with context.'''\n    settings = await load_settings()\n    return json.dumps(settings.get(key, {}))\n```\n\n**When to use Resources vs Tools:**\n- **Resources**: For data access with simple parameters (URI templates)\n- **Tools**: For complex operations with validation and business logic\n\n### Structured Output Types\n\nFastMCP supports multiple return types beyond strings:\n\n```python\nfrom typing import TypedDict\nfrom dataclasses import dataclass\nfrom pydantic import BaseModel\n\n# TypedDict for structured returns\nclass UserData(TypedDict):\n    id: str\n    name: str\n    email: str\n\n@mcp.tool()\nasync def get_user_typed(user_id: str) -> UserData:\n    '''Returns structured data - FastMCP handles serialization.'''\n    return {\"id\": user_id, \"name\": \"John Doe\", \"email\": \"john@example.com\"}\n\n# Pydantic models for complex validation\nclass DetailedUser(BaseModel):\n    id: str\n    name: str\n    email: str\n    created_at: datetime\n    metadata: Dict[str, Any]\n\n@mcp.tool()\nasync def get_user_detailed(user_id: str) -> DetailedUser:\n    '''Returns Pydantic model - automatically generates schema.'''\n    user = await fetch_user(user_id)\n    return DetailedUser(**user)\n```\n\n### Lifespan Management\n\nInitialize resources that persist across requests:\n\n```python\nfrom contextlib import asynccontextmanager\n\n@asynccontextmanager\nasync def app_lifespan():\n    '''Manage resources that live for the server's lifetime.'''\n    # Initialize connections, load config, etc.\n    db = await connect_to_database()\n    config = load_configuration()\n\n    # Make available to all tools\n    yield {\"db\": db, \"config\": config}\n\n    # Cleanup on shutdown\n    await db.close()\n\nmcp = FastMCP(\"example_mcp\", lifespan=app_lifespan)\n\n@mcp.tool()\nasync def query_data(query: str, ctx: Context) -> str:\n    '''Access lifespan resources through context.'''\n    db = ctx.request_context.lifespan_state[\"db\"]\n    results = await db.query(query)\n    return format_results(results)\n```\n\n### Transport Options\n\nFastMCP supports two main transport mechanisms:\n\n```python\n# stdio transport (for local tools) - default\nif __name__ == \"__main__\":\n    mcp.run()\n\n# Streamable HTTP transport (for remote servers)\nif __name__ == \"__main__\":\n    mcp.run(transport=\"streamable_http\", port=8000)\n```\n\n**Transport selection:**\n- **stdio**: Command-line tools, local integrations, subprocess execution\n- **Streamable HTTP**: Web services, remote access, multiple clients\n\n---\n\n## Code Best Practices\n\n### Code Composability and Reusability\n\nYour implementation MUST prioritize composability and code reuse:\n\n1. **Extract Common Functionality**:\n   - Create reusable helper functions for operations used across multiple tools\n   - Build shared API clients for HTTP requests instead of duplicating code\n   - Centralize error handling logic in utility functions\n   - Extract business logic into dedicated functions that can be composed\n   - Extract shared markdown or JSON field selection & formatting functionality\n\n2. **Avoid Duplication**:\n   - NEVER copy-paste similar code between tools\n   - If you find yourself writing similar logic twice, extract it into a function\n   - Common operations like pagination, filtering, field selection, and formatting should be shared\n   - Authentication/authorization logic should be centralized\n\n### Python-Specific Best Practices\n\n1. **Use Type Hints**: Always include type annotations for function parameters and return values\n2. **Pydantic Models**: Define clear Pydantic models for all input validation\n3. **Avoid Manual Validation**: Let Pydantic handle input validation with constraints\n4. **Proper Imports**: Group imports (standard library, third-party, local)\n5. **Error Handling**: Use specific exception types (httpx.HTTPStatusError, not generic Exception)\n6. **Async Context Managers**: Use `async with` for resources that need cleanup\n7. **Constants**: Define module-level constants in UPPER_CASE\n\n## Quality Checklist\n\nBefore finalizing your Python MCP server implementation, ensure:\n\n### Strategic Design\n- [ ] Tools enable complete workflows, not just API endpoint wrappers\n- [ ] Tool names reflect natural task subdivisions\n- [ ] Response formats optimize for agent context efficiency\n- [ ] Human-readable identifiers used where appropriate\n- [ ] Error messages guide agents toward correct usage\n\n### Implementation Quality\n- [ ] FOCUSED IMPLEMENTATION: Most important and valuable tools implemented\n- [ ] All tools have descriptive names and documentation\n- [ ] Return types are consistent across similar operations\n- [ ] Error handling is implemented for all external calls\n- [ ] Server name follows format: `{service}_mcp`\n- [ ] All network operations use async/await\n- [ ] Common functionality is extracted into reusable functions\n- [ ] Error messages are clear, actionable, and educational\n- [ ] Outputs are properly validated and formatted\n\n### Tool Configuration\n- [ ] All tools implement 'name' and 'annotations' in the decorator\n- [ ] Annotations correctly set (readOnlyHint, destructiveHint, idempotentHint, openWorldHint)\n- [ ] All tools use Pydantic BaseModel for input validation with Field() definitions\n- [ ] All Pydantic Fields have explicit types and descriptions with constraints\n- [ ] All tools have comprehensive docstrings with explicit input/output types\n- [ ] Docstrings include complete schema structure for dict/JSON returns\n- [ ] Pydantic models handle input validation (no manual validation needed)\n\n### Advanced Features (where applicable)\n- [ ] Context injection used for logging, progress, or elicitation\n- [ ] Resources registered for appropriate data endpoints\n- [ ] Lifespan management implemented for persistent connections\n- [ ] Structured output types used (TypedDict, Pydantic models)\n- [ ] Appropriate transport configured (stdio or streamable HTTP)\n\n### Code Quality\n- [ ] File includes proper imports including Pydantic imports\n- [ ] Pagination is properly implemented where applicable\n- [ ] Filtering options are provided for potentially large result sets\n- [ ] All async functions are properly defined with `async def`\n- [ ] HTTP client usage follows async patterns with proper context managers\n- [ ] Type hints are used throughout the code\n- [ ] Constants are defined at module level in UPPER_CASE\n\n### Testing\n- [ ] Server runs successfully: `python your_server.py --help`\n- [ ] All imports resolve correctly\n- [ ] Sample tool calls work as expected\n- [ ] Error scenarios handled gracefully\n","core/skills/builtin/review-agent/SKILL.md":"---\nname: review-agent\ndescription: Perform a read-only, defect-first review of a specified code change and return every actionable finding. Use when another agent delegates review of uncommitted changes, a base-branch diff, a commit, or custom review instructions.\n---\n\n# Review Agent\n\nInspect the requested target directly and return every finding that the author would likely fix.\nDo not modify files, create commits, push branches, post review comments, or delegate the review\nto another agent.\n\n## Review the change\n\n1. Read the applicable `AGENTS.md` instructions.\n2. Inspect the complete diff for the requested target and enough surrounding code to understand\n   each changed path.\n3. Identify concrete regressions introduced by the change. Continue through the whole diff after\n   finding the first issue.\n4. Check the relevant tests and call sites to confirm that each finding is real and actionable.\n\nFor a base-branch review, compare the changes that would actually merge rather than diffing\ndirectly against the branch tip. Resolve the comparison ref to the branch's upstream when that\nupstream exists and is ahead of the local branch; otherwise use the local branch. Run\n`git merge-base HEAD <comparison-ref>`, then inspect `git diff <merge-base-sha>`. If the local\nbranch cannot be resolved, try its configured upstream explicitly before reporting that the target\nis unavailable.\n\nFlag an issue only when all of these are true:\n\n- It affects correctness, security, performance, or maintainability in a meaningful way.\n- It is discrete and actionable.\n- It was introduced by the reviewed change.\n- The affected scenario or call path can be demonstrated from the code.\n- The author would probably fix it if they knew about it.\n\nDo not flag speculative concerns, pre-existing problems, intentional behavior changes, or style\nnits that do not obscure the code.\n\n## Write the result\n\nPresent findings first, ordered by severity. Use one entry per issue in this form:\n\n`[P1] Imperative finding title — path/to/file.rs:line`\n\nFollow the title with one short paragraph explaining the affected scenario and why the behavior is\nwrong. Keep the cited range as small as possible and make sure it overlaps the reviewed diff.\n\nUse these priorities:\n\n- `P0`: universal release blocker or critical failure.\n- `P1`: urgent defect that should be fixed next.\n- `P2`: ordinary defect that should be fixed.\n- `P3`: low-impact issue that is still worth fixing.\n\nIf there are no qualifying findings, say `No findings.` Do not invent a finding to fill the result.\nAfter the findings, add a brief overall assessment and mention any material test gaps or residual\nrisks.\n","core/skills/builtin/review-agent/agents/openai.yaml":"interface:\n  display_name: \"Review Agent\"\n  short_description: \"Find actionable bugs in code changes\"\n  default_prompt: \"Use $review-agent to review the requested code changes and return actionable findings.\"\npolicy:\n  allow_implicit_invocation: false\n","core/skills/builtin/security-best-practices/SKILL.md":"---\nname: \"security-best-practices\"\ndescription: \"Perform language and framework specific security best-practice reviews and suggest improvements. Trigger only when the user explicitly requests security best practices guidance, a security review/report, or secure-by-default coding help. Trigger only for supported languages (python, javascript/typescript, go). Do not trigger for general code review, debugging, or non-security tasks.\"\n---\n\n# Security Best Practices\n\n## Overview\n\nThis skill provides a description of how to identify the language and frameworks used by the current context, and then to load information from this skill's references directory about the security best practices for this language and or frameworks.\n\nThis information, if present, can be used to write new secure by default code, or to passively detect major issues within existing code, or (if requested by the user) provide a vulnerability report and suggest fixes.\n\n## Workflow\n\nThe initial step for this skill is to identify ALL languages and ALL frameworks which you are being asked to use or already exist in the scope of the project you are working in. Focus on the primary core frameworks. Often you will want to identify both frontend and backend languages and frameworks.\n\nThen check this skill's references directory to see if there are any relevant documentation for the language and or frameworks. Make sure you read ALL reference files which relate to the specific framework or language. The format of the filenames is `<language>-<framework>-<stack>-security.md`. You should also check if there is a `<language>-general-<stack>-security.md` which is agnostic to the framework you may be using.\n\nIf working on a web application which includes a frontend and a backend, make sure you have checked for reference documents for BOTH the frontend and backend!\n\nIf you are asked to make a web app which will include both a frontend and backend, but the frontend framework is not specified, also check out `javascript-general-web-frontend-security.md`. It is important that you understand how to secure both the frontend and backend.\n\nIf no relevant information is available in the skill's references directory, think a little bit about what you know about the language, the framework, and all well known security best practices for it. If you are unsure you can try to search online for documentation on security best practices.\n\nFrom there it can operate in a few ways.\n\n1. The primary mode is to just use the information to write secure by default code from this point forward. This is useful for starting a new project or when writing new code.\n\n2. The secondary mode is to passively detect vulnerabilities while working in the project and writing code for the user. Critical or very important vulnerabilities or major issues going against security guidance can be flagged and the user can be told about them. This passive mode should focus on the largest impact vulnerabilities and secure defaults.\n\n3. The user can ask for a security report or to improve the security of the codebase. In this case a full report should be produced describe anyways the project fails to follow security best practices guidance. The report should be prioritized and have clear sections of severity and urgency. Then offer to start working on fixes for these issues. See #fixes below.\n\n## Workflow Decision Tree\n\n- If the language/framework is unclear, inspect the repo to determine it and list your evidence.\n- If matching guidance exists in `references/`, load only the relevant files and follow their instructions.\n- If no matching guidance exists, consider if you know any well known security best practices for the chosen language and or frameworks, but if asked to generate a report, let the user know that concrete guidance is not available (you can still generate the report or detect for sure critical vulnerabilities)\n\n# Overrides\n\nWhile these references contain the security best practices for languages and frameworks, customers may have cases where they need to bypass or override these practices. Pay attention to specific rules and instructions in the project's documentation and prompt files which may require you to override certain best practices. When overriding a best practice, you MAY report it to the user, but do not fight with them. If a security best practice needs to be bypassed / ignored for some project specific reason, you can also suggest to add documentation about this to the project so it is clear why the best practice is not being followed and to follow that bypass in the future.\n\n# Report Format\n\nWhen producing a report, you should write the report as a markdown file in `security_best_practices_report.md` or some other location if provided by the user. You can ask the user where they would like the report to be written to.\n\nThe report should have a short executive summary at the top.\n\nThe report should be clearly delineated into multiple sections based on severity of the vulnerability. The report should focus on the most critical findings as these have the highest impact for the user. All findings should be noted with an numeric ID to make them easier to reference.\n\nFor critical findings include a one sentence impact statement.\n\nOnce the report is written, also report it to the user directly, although you may be less verbose. You can offer to explain any of the findings or the reasons behind the security best practices guidance if the user wants more info on any findings.\n\nImportant: When referencing code in the report, make sure to find and include line numbers for the code you are referencing.\n\nAfter you write the report file, summarize the findings to the user.\n\nAlso tell the user where the final report was written to\n\n# Fixes\n\nIf you produced a report, let the user read the report and ask to begin performing fixes.\n\nIf you passively found a critical finding, notify the user and ask if they would like you to fix this finding.\n\nWhen producing fixes, focus on fixing a single finding at a time. The fixes should have concise clear comments explaining that the new code is based on the specific security best practice, and perhaps a very short reason why it would be dangerous to not do it in this way.\n\nAlways consider if the changes you want to make will impact the functionality of the user's code. Consider if the changes may cause regressions with how the project works currently. It is often the case that insecure code is relied on for other reasons (and this is why insecure code lives on for so long). Avoid breaking the user's project as this may make them not want to apply security fixes in the future. It is better to write a well thought out, well informed by the rest of the project, fix, then a quick slapdash change.\n\nAlways follow any normal change or commit flow the user has configured. If making git commits, provide clear commit messages explaining this is to align with security best practices. Try to avoid bunching a number of unrelated findings into a single commit.\n\nAlways follow any normal testing flows the user has configured (if any) to confirm that your changes are not introducing regressions. Consider the second order impacts the changes may have and inform the user before making them if there are any.\n\n# General Security Advice\n\nBelow is a few bits of secure coding advice that applies to almost any language or framework.\n\n### Avoid Using Incrementing IDs for Public IDs of Resources\n\nWhen assigning an ID for some resource, which will then be used by exposed to the internet, avoid using small auto-incrementing IDs. Use longer, random UUID4 or random hex string instead. This will prevent users from learning the quantity of a resource and being able to guess resource IDs.\n\n### A note on TLS\n\nWhile TLS is important for production deployments, most development work will be with TLS disabled or provided by some out-of-scope TLS proxy. Due to this, be very careful about not reporting lack of TLS as a security issue. Also be very careful around use of \"secure\" cookies. They should only be set if the application will actually be over TLS. If they are set on non-TLS applications (such as when deployed for local dev or testing), it will break the application. You can provide a env or other flag to override setting secure as a way to keep it off until on a TLS production deployment. Additionally avoid recommending HSTS. It is dangerous to use without full understanding of the lasting impacts (can cause major outages and user lockout) and it is not generally recommended for the scope of projects being reviewed by codex.\n","core/skills/builtin/security-best-practices/agents/openai.yaml":"interface:\n  display_name: \"Security Best Practices\"\n  short_description: \"Security reviews and secure-by-default guidance\"\n  default_prompt: \"Review this codebase for security best practices and suggest secure-by-default improvements.\"\n","core/skills/builtin/security-best-practices/references/golang-general-backend-security.md":"# Go (Golang) Security Spec (Go 1.25.x, Standard Library, net/http)\n\nThis document is designed as a **security spec** that supports:\n1) **Secure-by-default code generation** for new Go code.\n2) **Security review / vulnerability hunting** in existing Go code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n--------------------------------------------------------------------\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n- MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session cookies, JWTs, database URLs with credentials, signing keys, client secrets).\n- MUST NOT “fix” security by disabling protections (e.g., `InsecureSkipVerify`, `GOSUMDB=off` for public modules, wildcard CORS + credentials, removing auth checks, disabling CSRF defenses on cookie-auth apps).\n- MUST provide **evidence-based findings** during audits: cite file paths, code snippets, build/deploy configs, and concrete values that justify the claim.\n- MUST treat uncertainty honestly: if a control might exist in infrastructure (reverse proxy, WAF, service mesh, platform config), report it as “not visible in app code; verify at runtime/config.”\n- MUST keep fixes minimal, correct, and production-safe; avoid introducing breaking changes without warning (especially around auth/session flows, and proxies).\n\n--------------------------------------------------------------------\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\nWhen asked to write new Go code or modify existing code:\n- MUST follow every **MUST** requirement in this spec.\n- SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n- MUST prefer safe-by-default APIs and proven libraries over custom security code.\n- MUST avoid introducing new risky sinks (shell execution, dynamic template execution, serving user files as HTML, unsafe redirects, weak crypto, unbounded parsing, etc.).\n\n### 1.2 Passive review mode (always on while editing)\nWhile working anywhere in a Go repo (even if the user did not ask for a security scan):\n- MUST “notice” violations of this spec in touched/nearby code.\n- SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n- MUST systematically search the codebase for violations of this spec.\n- MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n1) Build/deploy entrypoints: `main.go`, `cmd/*`, Dockerfiles, Kubernetes manifests, systemd units, CI workflows.\n2) Go toolchain & dependency policy: Go version, modules, `go.mod/go.sum`, proxy/sumdb settings, govulncheck usage.\n3) Secret management and config loading (env, files, secret stores) + logging patterns.\n4) HTTP server configuration (timeouts, body limits, proxy trust, security headers).\n5) AuthN/AuthZ boundaries, session/cookie settings, token validation.\n6) CSRF protections for cookie-authenticated state-changing endpoints.\n7) Template usage and output encoding (XSS), and any “render template from string” behavior (SSTI).\n8) File handling (uploads/downloads/path traversal/temp files), static file serving.\n9) Injection sinks: SQL, OS command execution, SSRF/outbound fetch, open redirects.\n10) Concurrency/resource exhaustion (unbounded goroutines/queues, missing timeouts/contexts).\n11) Use of `unsafe` / `cgo` / `reflect` in security-sensitive paths.\n12) Debug/diagnostic endpoints (pprof/expvar/metrics) exposure.\n13) Cryptography usage (randomness, password hashing).\n\n--------------------------------------------------------------------\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\nExamples include:\n- `*http.Request` fields: `r.URL.Path`, `r.URL.RawQuery`, `r.Form`, `r.PostForm`, headers, cookies, `r.Body`\n- Path parameters from routers (including values extracted from URL paths)\n- JSON/XML/YAML bodies, multipart form parts, uploaded files\n- Any data from external systems (webhooks, third-party APIs, message queues)\n- Any persisted user content (DB rows) that originated from users\n- Configuration values that might be attacker-influenced in some deployments (headers set by upstream proxies, environment variables in multi-tenant systems)\n\n### 2.2 State-changing request\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook send), or initiate privileged actions.\n\n### 2.3 Required audit finding format\nFor each issue found, output:\n\n- Rule ID:\n- Severity: Critical / High / Medium / Low\n- Location: file path + function/handler name + line(s)\n- Evidence: the exact code/config snippet\n- Impact: what could go wrong, who can exploit it\n- Fix: safe change (prefer minimal diff)\n- Mitigation: defense-in-depth if immediate fix is hard\n- False positive notes: what to verify if uncertain (edge configs, proxy behavior, auth assumptions)\n\n--------------------------------------------------------------------\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common Go misconfigurations.\n\n### 3.1 Toolchain, patching, and dependency hygiene (MUST)\n- MUST run a supported Go major version and keep to the latest patch releases.\n- MUST treat Go standard library patch releases as security-relevant (many security fixes land in stdlib components like `net/http`, `crypto/*`, parsing packages).\n- MUST use Go modules with committed `go.mod` and `go.sum`.\n- MUST NOT disable module authenticity mechanisms for public modules (checksum DB) unless you have a controlled, documented replacement.\n- MUST run `govulncheck` (source scan and/or binary scan) in CI and address findings.\n\n### 3.2 HTTP server baseline (MUST for network-facing services)\nIf the program serves HTTP (directly or via a framework built on `net/http`):\n- MUST configure an `http.Server` with explicit timeouts and header limits.\n- MUST set request body size limits (global and per-route as needed).\n- MUST avoid exposing diagnostic endpoints (pprof/expvar) publicly.\n- SHOULD set a consistent set of security headers (or verify they are set at the edge).\n- MUST set cookie security attributes for any cookies you issue.\n- SHOULD implement rate limiting and abuse controls for auth and expensive endpoints.\n\nIllustrative baseline skeleton (adjust to your project):\n- Create a dedicated mux (avoid implicit global defaults unless intentionally managed).\n- Wrap handlers with: panic-safe error handling, request ID, logging, auth, and limits.\n\n--------------------------------------------------------------------\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### GO-DEPLOY-001: Keep the Go toolchain and standard library updated (security releases)\nSeverity: Medium\n\nNOTE: Upgrading dependencies and the core Go version can break projects in unexpected ways. Focus on only security-critical dependencies and if noticed, let the user know rather than upgrading automatically.\n\nRequired:\n- MUST run a supported Go major release and apply patch releases promptly.\n- SHOULD treat patch releases as security-relevant, even if your application code didn’t change.\n\nInsecure patterns:\n- Production builds pinned to old Go versions without a patching process.\n- Docker images like `golang:1.xx` or custom base images that are not updated regularly.\n- CI pipelines that intentionally suppress Go updates.\n\nDetection hints:\n- Inspect CI (`.github/workflows`, `gitlab-ci.yml`, etc.) for `go-version:` or toolchain setup.\n- Inspect Dockerfiles for `FROM golang:` tags.\n- Inspect `go.mod` `go` directive and any toolchain pinning.\n\nFix:\n- Upgrade to the latest patch of a supported Go version.\n- Add an automated check (CI) that fails when Go is below an approved minimum.\n\nNotes:\n- Go publishes regular minor releases that frequently include security fixes across standard library packages.\n\n---\n\n### GO-SUPPLY-001: Go module authenticity MUST NOT be disabled for public dependencies\nSeverity: High\n\nRequired:\n- MUST keep module checksum verification enabled for public modules.\n- SHOULD commit `go.sum` and treat changes as security-sensitive.\n- MUST NOT use insecure module fetching settings for public modules.\n- MAY configure private module behavior using `GOPRIVATE`/`GONOSUMDB` for private repos, but must do so narrowly and intentionally.\n\nInsecure patterns:\n- `GOSUMDB=off` in CI or production build environments for public modules.\n- `GONOSUMDB=*` or overly broad patterns that effectively disable verification.\n- `GOINSECURE=*` or broad `GOINSECURE` patterns for public modules.\n- `GOPROXY=direct` everywhere without a clear policy.\n\nDetection hints:\n- Search build configs for `GOSUMDB`, `GONOSUMDB`, `GOINSECURE`, `GOPROXY`, `GOPRIVATE`.\n- Look for documentation/scripts that recommend disabling checksum DB “to make builds work”.\n\nFix:\n- Restore defaults for public module verification.\n- For private modules:\n  - Set `GOPRIVATE=your.private.domain/*`\n  - Configure an internal proxy or direct fetching, and restrict `GONOSUMDB` to private patterns only.\n\nNotes:\n- Disabling checksum verification removes an important integrity layer against targeted or compromised upstream delivery.\n\n---\n\n### GO-CONFIG-001: Secrets must be externalized and never logged or committed\nSeverity: High (Critical if credentials are committed)\n\nRequired:\n- MUST load secrets from environment variables, secret managers, or secure config files with restricted permissions.\n- MUST NOT hard-code secrets in Go source, test fixtures that may reach production, or build args.\n- MUST NOT log secrets or full credential-bearing connection strings.\n- SHOULD fail closed in production if required secrets are missing.\n\nInsecure patterns:\n- String constants containing tokens/keys/passwords.\n- `.env` files or config files with secrets committed to repo.\n- Logging `os.Environ()`, dumping full configs, or printing DSNs.\n\nDetection hints:\n- Search for suspicious literals (`API_KEY`, `SECRET`, `PASSWORD`, `Authorization:`).\n- Inspect config loaders and logging statements.\n- Inspect CI logs or debug print paths.\n\nFix:\n- Move secrets to a secret store / environment variables.\n- Redact sensitive fields in logs.\n- Add secret scanning to CI and pre-commit.\n\n---\n\n### GO-HTTP-001: HTTP servers MUST set timeouts and MaxHeaderBytes\nSeverity: High (DoS risk)\n\nRequired:\n- MUST set: `ReadHeaderTimeout`, and SHOULD set `ReadTimeout`, `WriteTimeout`, `IdleTimeout` as appropriate for the service.\n- MUST set `MaxHeaderBytes` to a justified limit for your application.\n- MUST NOT rely on default zero-values for timeouts in production for internet-facing servers.\n\nInsecure patterns:\n- `http.ListenAndServe(\":8080\", handler)` with a default `http.Server` (no explicit timeouts).\n- `&http.Server{}` with timeouts left at zero.\n- Missing `MaxHeaderBytes`.\n\nDetection hints:\n- Search for `http.ListenAndServe(`, `ListenAndServeTLS(`, `Server{` and inspect configured fields.\n- Check for reverse proxies; even with a proxy, app-level timeouts still matter.\n\nFix:\n- Use `http.Server{ReadHeaderTimeout: ..., ReadTimeout: ..., WriteTimeout: ..., IdleTimeout: ..., MaxHeaderBytes: ...}`.\n- Calibrate timeouts per endpoint type (streaming vs JSON APIs).\n\nNotes:\n- Net/http documents that these timeouts exist and that zero/negative values mean “no timeout”; production services should choose explicit values.\n\n---\n\n### GO-HTTP-002: Request body and multipart parsing MUST be size-bounded\nSeverity: Medium (DoS risk; can be High for upload-heavy apps)\n\nRequired:\n- MUST enforce a global maximum request body size for endpoints that accept bodies.\n- MUST enforce strict multipart upload limits and avoid unbounded form parsing.\n- SHOULD enforce per-route limits when some endpoints legitimately need larger bodies.\n- SHOULD set upstream (proxy) limits as defense-in-depth.\n\nInsecure patterns:\n- Reading `r.Body` with `io.ReadAll(r.Body)` without a size cap.\n- Calling `r.ParseMultipartForm(...)` with overly large limits (or forgetting size controls).\n- Accepting file uploads with no limits on file size, number of parts, or total body size.\n\nDetection hints:\n- Search for `io.ReadAll(r.Body)`, `json.NewDecoder(r.Body)`, `ParseMultipartForm`, `FormFile`, `multipart`.\n- Look for missing `http.MaxBytesReader` or equivalent per-handler limiting.\n- Look for “upload” endpoints and check limits.\n\nFix:\n- Wrap request bodies with `http.MaxBytesReader(w, r.Body, maxBytes)` before parsing.\n- For multipart, set conservative limits and validate file sizes/part counts explicitly.\n- Set proxy limits (e.g., at ingress) in addition to app limits.\n\nNotes:\n- There are known vulnerability classes and advisories related to excessive resource consumption in multipart/form parsing; treat unbounded parsing as a security issue.\n\n---\n\n### GO-DEPLOY-002: Diagnostic endpoints (pprof/expvar/metrics) MUST NOT be publicly exposed\nSeverity: High\n\nNOTE: This only applies to production configurations. These endpoints are often used for debug or dev endpoints. If found, confirm that it would be reachable from the actual production deployment.\n\nRequired:\n- MUST NOT expose `net/http/pprof` handlers on a public internet-facing listener without strong access controls.\n- SHOULD run diagnostics on a separate, internal-only listener (loopback/VPC-only) and require auth.\n- MUST review what diagnostic endpoints reveal (stack traces, memory, command lines, environment, internal URLs).\n\nInsecure patterns:\n- Side-effect import `import _ \"net/http/pprof\"` in a server binary with a public mux.\n- `/debug/pprof/*` reachable without auth.\n- `/debug/vars` (expvar) reachable without auth.\n\nDetection hints:\n- Search for `net/http/pprof` imports (including blank imports).\n- Search for route prefixes `/debug/pprof`, `/debug/vars`.\n- Check whether `http.DefaultServeMux` is used and whether any debug handlers register globally.\n\nFix:\n- Remove diagnostics from production builds, or bind them to an internal-only listener.\n- Add strong authentication/authorization (and ideally network-level restrictions).\n\nNotes:\n- pprof is typically imported for its side effect of registering HTTP handlers under `/debug/pprof/`.\n\n---\n\n### GO-HTTP-003: Reverse proxy and forwarded header trust MUST be explicit\nSeverity: High (auth, URL generation, logging/auditing correctness)\n\nRequired:\n- If behind a reverse proxy, MUST define which proxy is trusted and how client IP/scheme/host are derived.\n- MUST NOT trust `X-Forwarded-For`, `X-Forwarded-Proto`, `Forwarded`, or similar headers from the open internet.\n- MUST ensure “secure cookie” logic, redirects, and absolute URL generation do not rely on spoofable headers.\n\nInsecure patterns:\n- Using `r.Header.Get(\"X-Forwarded-For\")` as the client IP without validating the proxy boundary.\n- Deriving “is HTTPS” from `X-Forwarded-Proto` without confirming it came from a trusted proxy.\n- Using forwarded `Host` values for password reset links without allowlisting.\n\nDetection hints:\n- Search for `X-Forwarded-For`, `X-Forwarded-Proto`, `Forwarded`, `Real-IP`, and any custom “client IP” helpers.\n- Inspect ingress/proxy configs; if not visible, mark as “verify at edge”.\n\nFix:\n- Enforce proxy trust at the edge and in app:\n  - Accept forwarded headers only from known proxy IP ranges.\n  - Prefer platform-provided mechanisms where available.\n- If generating external links, use a configured allowlisted canonical origin (not the request’s Host header).\n\n---\n\n### GO-HTTP-004: Security headers SHOULD be set (in app or at the edge)\nSeverity: Medium\n\nRequired (typical web app serving browsers):\n- SHOULD set:\n  - `Content-Security-Policy` (CSP) appropriate to the app. NOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n  - `X-Content-Type-Options: nosniff`\n  - Clickjacking protection (`X-Frame-Options` and/or CSP `frame-ancestors`)\n  - `Referrer-Policy` and `Permissions-Policy` where appropriate\n- MUST ensure cookies have secure attributes (see GO-HTTP-005).\n\nNOTE:\n- These headers may be set via reverse proxy/CDN; if not visible in app code, report as “verify at edge”.\n\nInsecure patterns:\n- No security headers anywhere (app or edge) for a browser-facing app.\n- CSP missing for apps rendering untrusted content.\n\nDetection hints:\n- Search for middleware setting headers: `w.Header().Set(\"Content-Security-Policy\", ...)`, etc.\n- Search for reverse proxy config that sets headers.\n\nFix:\n- Add centralized header middleware in Go, or configure at the edge.\n- Keep CSP realistic; avoid `unsafe-inline` where possible.\n\n---\n\n### GO-HTTP-005: Cookies MUST use secure attributes in production\nSeverity: Medium\n\nRequired (production, HTTPS):\n- MUST set `Secure` on cookies that carry auth/session state. IMPORTANT NOTE: Only set `Secure` in production environment when TLS is configured. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n- MUST set `HttpOnly` on auth/session cookies.\n- SHOULD set `SameSite=Lax` by default (or `Strict` if compatible), and only use `None` when necessary (and only with `Secure`).\n- SHOULD set bounded lifetimes (`Max-Age`/`Expires`) appropriate to the app.\n\nInsecure patterns:\n- Setting auth/session cookies without `Secure` in HTTPS deployments.\n- Cookies without `HttpOnly` for session identifiers.\n- `SameSite=None` for cookie-authenticated apps without a strong CSRF strategy.\n\nDetection hints:\n- Search for `http.SetCookie`, `&http.Cookie{`, `Set-Cookie`.\n- Inspect cookie flags in auth/session code.\n\nFix:\n- Set the correct fields on `http.Cookie` and centralize cookie creation.\n\nNotes:\n- SameSite is defense-in-depth and does not replace CSRF protections for cookie-auth apps.\n\n---\n\n### GO-HTTP-006: Cookie-authenticated state-changing endpoints MUST be CSRF-protected\nSeverity: High\n\n- IMPORTANT NOTE: If cookies are not used for auth (e.g., pure bearer token in Authorization header with no ambient cookies), CSRF is not a risk for those endpoints.\n\nRequired:\n- MUST protect all state-changing endpoints (POST/PUT/PATCH/DELETE) that rely on cookies for authentication.\n- SHOULD use a well-tested CSRF library/middleware rather than rolling your own.\n- MAY use additional defenses (Origin/Referer checks, Fetch Metadata, SameSite cookies), but tokens remain the primary defense for cookie-authenticated apps.\nIf tokens are impractical, or for small applications:\n* MUST at a minimum require a custom header to be set and set the session cookie SESSION_COOKIE_SAMESITE=lax, as this is the strongest method besides requiring a form token, and may be much easier to implement.\n\n\nInsecure patterns:\n- Cookie-authenticated JSON endpoints that mutate state with no CSRF checks.\n- Using GET for state-changing actions.\n\nDetection hints:\n- Enumerate all non-GET routes and identify auth mechanism.\n- Look for CSRF middleware usage; if absent, treat as suspicious in browser-facing apps.\n\nFix:\n- Add CSRF middleware and ensure it covers all state-changing routes.\n- If the service is an API intended for non-browser clients, avoid cookie auth; use Authorization headers.\n\n---\n\n### GO-HTTP-007: CORS must be explicit and least-privilege\nSeverity: Medium (High if misconfigured with credentials)\n\nRequired:\n- If CORS is not needed, MUST keep it disabled.\n- If CORS is needed:\n  - MUST allowlist trusted origins (do not reflect arbitrary origins)\n  - MUST be careful with credentialed requests; do not combine broad origins with cookies\n  - SHOULD restrict allowed methods/headers\n\nInsecure patterns:\n- `Access-Control-Allow-Origin: *` paired with cookies (`Access-Control-Allow-Credentials: true`).\n- Reflecting `Origin` without validation.\n\nDetection hints:\n- Search for `Access-Control-Allow-` header setting.\n- Search for CORS middleware configuration.\n\nFix:\n- Implement strict origin allowlists and minimal methods/headers.\n- Ensure cookie-auth endpoints are not exposed cross-origin unless required.\n\n---\n\n### GO-XSS-001: Use html/template and avoid bypassing auto-escaping with untrusted data\nSeverity: High\n\nRequired:\n- MUST use `html/template` for HTML rendering (not `text/template`).\n- MUST NOT convert untrusted data into “trusted” template types (`template.HTML`, `template.JS`, `template.URL`, etc.).\n- SHOULD keep templates static and controlled by developers; treat dynamic templates as high risk.\n- MUST NOT serve user-uploaded HTML/JS as active content unless explicitly intended and safely sandboxed.\n\nInsecure patterns:\n- `text/template` used to generate HTML.\n- Using `template.HTML(userInput)` or similar typed wrappers.\n- Directly writing unescaped user content into HTML responses.\n\nDetection hints:\n- Search for `text/template`, `template.New(...).Parse(...)`, and typed wrappers like `template.HTML(`.\n- Inspect handlers that return HTML with string concatenation.\n\nFix:\n- Use `html/template` and pass untrusted data as data, not markup.\n- If you must allow limited HTML, use a vetted HTML sanitizer and still be careful with attributes/URLs.\n\n---\n\n### GO-SSTI-001: Never parse/execute templates from untrusted input (SSTI)\nSeverity: Critical\n\nRequired:\n- MUST NOT call `template.Parse` / `template.ParseFiles` / `template.New(...).Parse(...)` on template text influenced by untrusted input.\n- MUST treat “user-defined templates” as a special high-risk design:\n  - MUST use heavy sandboxing and strict allowlists\n  - MUST isolate execution (process/container boundary) if truly required\n\nInsecure patterns:\n- `tmpl := template.Must(template.New(\"x\").Parse(r.FormValue(\"tmpl\")))`\n- Reading templates from uploads / DB entries and executing them in the same trust domain as server code.\n\nDetection hints:\n- Search for `.Parse(` and trace the origin of the template string.\n- Look for “custom email templates”, “user theming templates”, etc.\n\nFix:\n- Replace with safe substitution mechanisms (no code execution).\n- If templates must be user-controlled, isolate and sandbox aggressively.\n\n---\n\n### GO-PATH-001: Prevent path traversal and unsafe file serving\nSeverity: High\n\nRequired:\n- MUST NOT pass user-controlled paths to `os.Open`, `os.ReadFile`, `http.ServeFile`, or `http.FileServer` without strict validation and base-dir enforcement.\n- MUST treat `..`, absolute paths, and OS-specific path tricks as hostile input.\n- SHOULD store user uploads outside any static web root; serve through controlled handlers.\n- MUST avoid directory listing for sensitive file trees.\n\nInsecure patterns:\n- `http.ServeFile(w, r, r.URL.Query().Get(\"path\"))`\n- `os.Open(filepath.Join(baseDir, userPath))` without checking that the result stays under `baseDir`\n- `http.FileServer(http.Dir(\".\"))` serving the project root or user-writable directories\n\nDetection hints:\n- Search for `ServeFile(`, `FileServer(`, `http.Dir(`, `os.Open(`, `ReadFile(`, `filepath.Join(`.\n- Trace whether path components come from request/DB.\n\nFix:\n- Use an allowlist of file identifiers (e.g., database IDs) mapped to server-side paths.\n- Enforce base directory containment after cleaning and joining.\n- Serve active formats as downloads (`Content-Disposition: attachment`) unless explicitly intended.\n\n---\n\n### GO-UPLOAD-001: File uploads must be validated, stored safely, and served safely\nSeverity: High\n\nRequired:\n- MUST enforce upload size limits (app + edge).\n- MUST validate file type using allowlists and content checks (not only extensions).\n- MUST store uploads outside executable/static roots when possible.\n- SHOULD generate server-side filenames (random IDs) and avoid trusting original names.\n- MUST serve potentially active formats safely (download attachment) unless explicitly intended.\n\nInsecure patterns:\n- Accepting arbitrary file types and serving them back inline.\n- Using user-supplied filename as storage path.\n- Missing size/type validation.\n\nDetection hints:\n- Search for `multipart`, `FormFile`, `ParseMultipartForm`, `io.Copy` to disk.\n- Check where files are stored and how they are served.\n\nFix:\n- Implement allowlist validation + safe storage + safe serving.\n- Add scanning/quarantine workflows where applicable.\n\n---\n\n### GO-INJECT-001: Prevent SQL injection (parameterized queries / ORM)\nSeverity: High\n\nRequired:\n- MUST use parameterized queries or an ORM that parameterizes under the hood.\n- MUST NOT build SQL by string concatenation / `fmt.Sprintf` / string interpolation with untrusted input.\n\nInsecure patterns:\n- `fmt.Sprintf(\"SELECT ... WHERE id=%s\", r.URL.Query().Get(\"id\"))`\n- `query := \"UPDATE users SET role='\" + role + \"' WHERE id=\" + id`\n\nDetection hints:\n- Grep for `SELECT`, `INSERT`, `UPDATE`, `DELETE` and check how query strings are built.\n- Trace untrusted data into `db.Query`, `db.Exec`, `QueryRow`, etc.\n\nFix:\n- Replace with placeholders (`?`, `$1`, etc.) and pass parameters separately.\n- Validate and type-check IDs before use.\n\n---\n\n### GO-INJECT-002: Prevent OS command injection; avoid shelling out with untrusted input\nSeverity: Critical to High (depends on exposure)\n\nRequired:\n- MUST avoid executing external commands with attacker-controlled strings.\n- If subprocess is necessary:\n  - MUST use `exec.CommandContext` with an argument list (not `sh -c`).\n  - MUST NOT pass untrusted input to a shell (`bash -c`, `sh -c`, PowerShell).\n  - SHOULD use strict allowlists for any variable component (subcommand, flags, filenames).\n- MUST assume CLI tools may interpret attacker-controlled args as flags or special values.\n\nInsecure patterns:\n- `exec.Command(\"sh\", \"-c\", userString)`\n- `exec.Command(\"bash\", \"-c\", fmt.Sprintf(\"tool %s\", user))`\n- Calling the shell to get glob expansion for user-supplied globs.\n\nDetection hints:\n- Search for `os/exec`, `exec.Command(`, `CommandContext(`, `\"sh\"`, `\"bash\"`, `\"-c\"`.\n- Trace untrusted input into command name/args.\n\nFix:\n- Use library APIs instead of subprocesses.\n- Hardcode command and allowlist/validate args.\n- If a shell is unavoidable, escape robustly and treat as high risk (prefer avoiding).\n\nNotes:\n- The Go `os/exec` package intentionally does invoke a shell; introducing `sh -c` reintroduces shell injection hazards.\n\n---\n\n### GO-SSRF-001: Prevent SSRF in outbound HTTP requests\nSeverity: Medium (High in cloud/LAN environments)\n\n- Note: For small stand alone projects this is less important. It is most important when deploying into an LAN or with other services listening on the same server.\n\nRequired:\n- MUST treat outbound requests to user-provided URLs as high risk.\n- SHOULD allowlist hosts/domains for any user-influenced URL fetch.\n- SHOULD block access to localhost/private IP ranges/link-local addresses and cloud metadata endpoints.\n- MUST restrict schemes to `http`/`https` (no `file:`, `gopher:`, etc.).\n- MUST set client timeouts and restrict redirects.\n\nInsecure patterns:\n- `http.Get(r.URL.Query().Get(\"url\"))`\n- “URL preview” / “webhook test” endpoints that fetch arbitrary URLs.\n\nDetection hints:\n- Search for `http.Get`, `client.Do`, and URL values derived from requests/DB.\n- Identify features that fetch remote resources.\n\nFix:\n- Parse URLs strictly; enforce scheme and allowlisted hostnames.\n- Resolve DNS and enforce IP-range restrictions (with care for DNS rebinding).\n- Set timeouts, disable redirects unless needed, and cap response sizes.\n\n---\n\n### GO-HTTPCLIENT-001: Outbound HTTP clients MUST set timeouts and close bodies\nSeverity: High (DoS and resource exhaustion)\n\nRequired:\n- MUST set an overall timeout on `http.Client` usage (or equivalent per-request deadlines via context + transport timeouts).\n- MUST ensure `resp.Body.Close()` is called for all successful requests (typically `defer resp.Body.Close()` immediately after error check).\n- SHOULD limit response body reads (do not `io.ReadAll` unbounded responses).\n- SHOULD restrict redirects for security-sensitive fetches (SSRF, auth flows).\n\nInsecure patterns:\n- Using `http.DefaultClient` / `http.Get` for user-influenced destinations with no timeout policy.\n- Missing `defer resp.Body.Close()` leading to resource leaks.\n- `io.ReadAll(resp.Body)` with no limit.\n\nDetection hints:\n- Search for `http.Get(`, `http.Post(`, `client := &http.Client{}` without `Timeout`, `client.Do(` and missing closes.\n- Search for `io.ReadAll(resp.Body)`.\n\nFix:\n- Use a configured client with timeouts.\n- Always close response bodies.\n- Use bounded readers (`io.LimitReader`) for large/untrusted responses.\n\nNotes:\n- The net/http package exposes `DefaultClient` as a zero-valued `http.Client`, which can easily lead to “no timeout” behavior unless configured.\n\n---\n\n### GO-REDIRECT-001: Prevent open redirects\nSeverity: Medium (can be High with auth flows)\n\nRequired:\n- MUST validate redirect targets derived from untrusted input (`next`, `redirect`, `return_to`).\n- SHOULD prefer only same-site relative paths.\n- SHOULD fall back to a safe default on validation failure.\n\nInsecure patterns:\n- `http.Redirect(w, r, r.URL.Query().Get(\"next\"), http.StatusFound)` with no validation.\n\nDetection hints:\n- Search for `http.Redirect(` and check origin of the location.\n\nFix:\n- Allowlist internal paths or known domains.\n- Reject absolute URLs unless explicitly needed and allowlisted.\n\n---\n\n### GO-CRYPTO-001: Cryptographic randomness MUST come from crypto/rand\nSeverity: High (Critical if used for auth/session tokens or keys)\n\nRequired:\n- MUST use `crypto/rand` for:\n  - session IDs, password reset tokens, API keys, CSRF tokens, nonces\n  - encryption keys, signing keys, salts when required\n- MUST NOT use `math/rand` for any security-sensitive value.\n- SHOULD use built-in helpers that produce appropriately strong tokens when available.\n\nInsecure patterns:\n- `math/rand.Seed(time.Now().UnixNano())` followed by token generation for auth or sessions.\n- Using UUIDv4-like constructs built from `math/rand`.\n\nDetection hints:\n- Search for `math/rand`, `rand.Seed`, `rand.Intn` in code that touches auth/session/token flows.\n- Search for custom token generators.\n\nFix:\n- Switch to `crypto/rand` (`rand.Reader`, `rand.Read`, or secure token helpers).\n- Ensure sufficient entropy and use URL-safe encoding.\n\nNotes:\n- The crypto/rand package provides secure randomness APIs and token generation helpers.\n\n---\n\n### GO-AUTH-001: Password storage MUST use adaptive hashing (bcrypt/argon2id) and safe comparisons\nSeverity: High\n\nRequired:\n- MUST hash passwords using an adaptive password hashing function (bcrypt or argon2id).\n- MUST NOT store plaintext passwords or reversible encryption of passwords.\n- MUST compare secrets in constant time when relevant (tokens, MACs, API keys) to reduce timing leaks.\n- SHOULD ensure password policies do not exceed algorithm constraints (e.g., bcrypt has input length limits; handle long passphrases appropriately).\n\nInsecure patterns:\n- `sha256(password)` stored as password hash.\n- Plaintext password storage.\n- Comparing secrets with `==` in timing-sensitive contexts.\n\nDetection hints:\n- Search for `sha1`, `sha256`, `md5` used on passwords.\n- Search for `bcrypt`/`argon2` usage; if absent, suspect.\n- Search for `==` comparisons on tokens/API keys.\n\nFix:\n- Use `bcrypt.GenerateFromPassword` / `CompareHashAndPassword` or argon2id with recommended parameters.\n- Use constant-time compare helpers when comparing MACs/tokens.\n\nNotes:\n- Go provides bcrypt in `golang.org/x/crypto/bcrypt`, and constant-time comparisons in `crypto/subtle`.\n\n---\n\n### GO-CONC-001: Data races and concurrency hazards MUST be treated as security-relevant\nSeverity: Medium to High (depends on what races affect)\n\nRequired:\n- MUST run tests with the race detector (`go test -race`) in CI for security-sensitive services.\n- MUST fix detected races; do not suppress without deep justification.\n- SHOULD treat shared mutable state in handlers as high risk; enforce synchronization or avoid shared mutability.\n\nInsecure patterns:\n- Global maps/slices mutated from multiple goroutines without a mutex.\n- Caches or auth/session state stored in globals without concurrency protection.\n- Racy access to authorization state (can lead to bypasses or inconsistent enforcement).\n\nDetection hints:\n- Search for `var someMap = map[...]...` used in handlers.\n- Look for missing `sync.Mutex`, `sync.Map`, channels, or other synchronization.\n- Ensure CI includes `-race` and that it runs relevant tests.\n\nFix:\n- Add proper synchronization or redesign to avoid shared mutable state.\n- Add race tests and run them continuously.\n\nNotes:\n- The Go race detector only finds races that occur in executed code paths; improve test coverage and run realistic workloads with `-race` where feasible.\n\n---\n\n### GO-UNSAFE-001: Use of unsafe/cgo MUST be minimized and audited like memory-unsafe code\nSeverity: High (Critical in high-risk code paths)\n\nRequired:\n- SHOULD avoid importing `unsafe` in application code unless absolutely necessary.\n- If `unsafe` is used, MUST treat it as “manual memory safety” requiring careful review and test coverage.\n- If `cgo` is used, MUST treat the C/C++ boundary as memory-unsafe; apply secure coding practices on the C side and isolate where possible.\n\nInsecure patterns:\n- Widespread `unsafe.Pointer` casts in parsing, serialization, auth, or network code.\n- `cgo` used for parsing or security boundaries without sandboxing.\n\nDetection hints:\n- Search for `import \"unsafe\"`, `unsafe.Pointer`, `// #cgo`, `import \"C\"`.\n- Prioritize review where unsafe touches untrusted input.\n\nFix:\n- Replace unsafe/cgo usage with safe standard library alternatives where possible.\n- Isolate unsafe code in small, well-tested modules with fuzz/race tests.\n\nNotes:\n- The unsafe package explicitly provides operations that step around Go’s type safety guarantees.\n\n--------------------------------------------------------------------\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\nToolchain & dependencies:\n- `FROM golang:` (Dockerfiles), `go-version:` (CI), `toolchain go` (go.mod), pinned old versions\n- `GOSUMDB=off`, `GOINSECURE`, `GONOSUMDB`, `GOPROXY=direct`\n- `replace` directives in `go.mod` to forks/paths\n- `govulncheck` missing in CI\n\nHTTP server hardening:\n- `http.ListenAndServe(`, `ListenAndServeTLS(`, `&http.Server{` with missing timeouts\n- `ReadHeaderTimeout: 0`, `ReadTimeout: 0`, `WriteTimeout: 0`, `IdleTimeout: 0`, missing `MaxHeaderBytes`\n\nBody parsing / DoS:\n- `io.ReadAll(r.Body)`, `json.NewDecoder(r.Body)` without size cap\n- `ParseMultipartForm`, `FormFile`, `multipart.NewReader` without explicit limits\n- Missing `http.MaxBytesReader`\n\nDebug exposure:\n- `import _ \"net/http/pprof\"`\n- `/debug/pprof`, `/debug/vars`\n\nTemplates / XSS / SSTI:\n- `text/template` used for HTML output\n- `template.HTML(`, `template.JS(`, `template.URL(` with user-controlled data\n- `.Parse(` on user-controlled strings\n\nFiles:\n- `http.ServeFile(` with user path\n- `http.FileServer(http.Dir(` pointing at repo root or uploads\n- `os.Open(filepath.Join(base, user))` without containment checks\n\nInjection:\n- SQL building with `fmt.Sprintf`, string concatenation near `db.Query/Exec`\n- `exec.Command(\"sh\",\"-c\", ...)`, `exec.Command(\"bash\",\"-c\", ...)`\n\nSSRF / outbound HTTP:\n- `http.Get(userURL)`, `client.Do(req)` where URL comes from request/DB\n- Missing client timeout, missing `resp.Body.Close()`, unbounded `io.ReadAll(resp.Body)`\n\nCrypto:\n- `math/rand` in token/session generation\n- `InsecureSkipVerify: true`\n- Password hashing with `sha256`/`md5` instead of bcrypt/argon2\n\nConcurrency:\n- Shared maps/slices mutated from handlers without locks\n- CI lacking `go test -race`\n\nAlways try to confirm:\n- data origin (untrusted vs trusted)\n- sink type (template/SQL/subprocess/files/http)\n- protective controls present (limits, validation, allowlists, middleware, network controls)\n\n--------------------------------------------------------------------\n\n## 6) Sources (accessed 2026-01-28)\n\nPrimary Go documentation:\n- Go Security Policy — https://go.dev/doc/security/policy\n- Go Release History (security fixes in patch releases) — https://go.dev/doc/devel/release\n- Go 1.25 Release Notes — https://go.dev/doc/go1.25\n- net/http (server timeouts, MaxHeaderBytes, DefaultClient) — https://pkg.go.dev/net/http\n- html/template (auto-escaping and trusted-template assumptions) — https://pkg.go.dev/html/template\n- crypto/tls (MinVersion defaults, InsecureSkipVerify warnings) — https://pkg.go.dev/crypto/tls\n- crypto/rand (secure randomness, token helpers) — https://pkg.go.dev/crypto/rand\n- crypto/subtle (constant-time comparisons) — https://pkg.go.dev/crypto/subtle\n- os/exec (no shell by default; command execution guidance) — https://pkg.go.dev/os/exec\n- unsafe (bypasses type safety) — https://go.dev/src/unsafe/unsafe.go\n- net/http/pprof (debug endpoints) — https://pkg.go.dev/net/http/pprof\n- cmd/go (module authentication via go.sum/checksum DB; env vars like GOINSECURE) — https://pkg.go.dev/cmd/go\n- Module Mirror and Checksum Database Launched (Go blog) — https://go.dev/blog/module-mirror-launch\n- govulncheck documentation — https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck\n- Go Race Detector documentation — https://go.dev/doc/articles/race_detector\n- bcrypt (password hashing) — https://pkg.go.dev/golang.org/x/crypto/bcrypt\n- Go vulnerability entry example (multipart resource consumption) — https://pkg.go.dev/vuln/GO-2023-1569\n\nOWASP Cheat Sheet Series (general web security):\n- Session Management — https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html\n- CSRF Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html\n- SSRF Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html\n- XSS Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html\n- HTTP Security Response Headers — https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html\n","core/skills/builtin/security-best-practices/references/javascript-express-web-server-security.md":"# Express (Node.js) Web Security Spec (Express 5.x / 4.19.2+, Node.js LTS)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new Express apps and routes.\n2. **Security review / vulnerability hunting** in existing Express code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session secrets, cookies, tokens).\n* MUST NOT “fix” security by disabling protections (e.g., weakening cookie flags, disabling CSRF defenses for cookie-authenticated apps, enabling permissive CORS, trusting proxy headers from the open internet, turning on debugging/stack traces in production, disabling TLS without a replacement).\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, middleware/config values, and runtime assumptions that justify the claim.\n* MUST treat uncertainty honestly: if a protection might exist in infrastructure (reverse proxy, gateway, WAF, CDN), report it as “not visible in app code; verify at runtime/config.”\n* MUST prefer vetted libraries and platform controls over “roll your own” crypto/auth/session/CSRF. Express explicitly expects the application to validate/handle user input correctly; it does not do this automatically. ([Express][1])\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new Express code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default APIs and proven libraries over custom security code.\n* MUST avoid introducing new risky sinks (shell execution, dynamic code evaluation, unsafe redirects, serving user files as HTML, template rendering from untrusted strings, unsafe filesystem paths, SSRF URL fetch endpoints, etc.).\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in an Express repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. Entrypoints (server/app bootstrap), deployment manifests, Dockerfiles, process manager config, CI/CD.\n2. Express settings + middleware stack order (helmet, parsers, auth, sessions, CSRF, CORS).\n3. Proxy trust (`trust proxy`) and IP/protocol/host handling. ([Express][2])\n4. Auth flows, sessions, cookies, password reset links, redirect handling. ([Express][1])\n5. State-changing routes + CSRF protections (cookie-authenticated apps). ([OWASP Cheat Sheet Series][3])\n6. Template rendering and XSS defenses (HTML generation, CSP, `res.locals`). ([OWASP Cheat Sheet Series][4])\n7. File handling (uploads + downloads + static files) and path traversal. ([Express][5])\n8. Injection classes (SQL, NoSQL, command execution, unsafe deserialization). ([OWASP Cheat Sheet Series][6])\n9. Outbound requests (SSRF) and webhook/callback delivery. ([OWASP Cheat Sheet Series][7])\n10. Rate limiting / brute-force defenses / abuse controls. ([Express][1])\n11. Dependency hygiene / lockfiles / npm audit / vulnerable Express versions. ([Express][1])\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nIn Express, common untrusted inputs include:\n\n* `req.params` (route parameters)\n* `req.query` (query string parameters; can be strings/arrays/objects depending on parsing) ([OWASP Cheat Sheet Series][8])\n* `req.body` from `express.json()`, `express.urlencoded()`, `express.text()`, `express.raw()` ([Express][5])\n* `req.headers` / `req.get(...)`\n* `req.cookies` / `req.signedCookies` (if cookie parsing middleware is used)\n* Upload metadata and filenames (e.g., multer `file.originalname`, `file.mimetype`)\n* Any data from external systems (webhooks, third-party APIs, message queues)\n* Any persisted user content (DB rows) that originated from users\n\nSpecial proxy note:\n\n* If `trust proxy` is enabled, values like `req.ip`, `req.hostname`, and `req.protocol` may be derived from `X-Forwarded-*` headers which **can be attacker-controlled** if your proxy chain is not correctly overwriting/removing them. ([Express][2])\n\n### 2.2 State-changing request\n\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook send), or initiate privileged actions.\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + function/route/middleware name + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common Express misconfigurations.\n\nMinimum baseline targets:\n\n* `helmet()` is used and configured (especially CSP where applicable), and fingerprinting is reduced (disable `x-powered-by`). ([Express][1])\n* A custom 404 handler and a custom error handler exist, and production does not leak internal stack traces. ([Express][1])\n* Cookie/session usage is deliberate:\n\n  * Not using default session cookie names\n  * Cookies use secure attributes (`Secure`, `HttpOnly`, `SameSite`) as appropriate\n  * Cookie-backed sessions never store secrets (they are readable by the client)\n  * Server-side sessions never use MemoryStore in production. ([Express][1])\n* Request body parsing has explicit limits (`express.json({ limit })`, `express.urlencoded({ limit, parameterLimit, depth })`). ([Express][5])\n* `trust proxy` is configured explicitly to match your proxy topology; not blindly `true`. ([Express][2])\n* Login/auth endpoints have brute-force protection and rate limiting. ([Express][1])\n* Dependencies are regularly audited/updated (`npm audit` + advisory response). ([Express][1])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### EXPRESS-INPUT-001: Treat all user input as untrusted and validate it\n\nSeverity: High\n\nRequired:\n\n* MUST validate and normalize untrusted inputs before using them in security-sensitive logic or dangerous sinks (DB queries, redirects, filesystem, HTML output, shell commands). Ensure the untrusted inputs are type checked and structure checked before using or passing forward.\n* SHOULD apply allowlists (known-good) rather than blocklists when feasible.\n* MUST reject or safely handle unexpected types/shapes in `req.query`, `req.params`, and `req.body`.\n\nInsecure patterns:\n\n* Passing `req.query`, `req.params`, `req.body` directly into database/query builders, redirects, filesystem paths, or templates.\n* Assuming `req.query.foo` is always a string (it can be an array/object depending on parsing). ([OWASP Cheat Sheet Series][8])\n\nDetection hints:\n\n* Identify “untrusted-to-sink” flows: request → sink (`res.redirect`, SQL execution, `sendFile`, `child_process`, template render, outbound fetch).\n* Search for direct usage of `req.query.*`, `req.body.*`, `req.params.*` in sensitive calls.\n\nFix:\n\n* Add schema validation (e.g., zod/joi/express-validator) at route boundaries.\n* Normalize types (e.g., force IDs to integers; reject arrays when scalar expected).\n\nNotes:\n\n* Express production security guidance explicitly says input validation/handling is the application’s responsibility. ([Express][1])\n\n---\n\n### EXPRESS-REDIRECT-001: Prevent open redirects; validate redirect targets\n\nSeverity: Medium\n\nRequired:\n\n* MUST validate redirect destinations derived from untrusted input (`next`, `return_to`, `url`).\n* SHOULD allowlist only same-site relative paths (preferred) or a strict allowlist of domains.\n* MUST fall back to a safe default when validation fails.\n\nInsecure patterns:\n\n* `res.redirect(req.query.next)` with no validation.\n* `res.redirect(req.body.url)` or `res.location(...)` using untrusted URLs.\n\nDetection hints:\n\n* Search for `res.redirect(` and `res.location(` and trace the source of the target.\n* Look for query params named `next`, `redirect`, `return`, `url`.\n\nFix:\n\n* Only allow relative paths (starting with `/`) and disallow `//`, backslashes, and encoded variants.\n* If cross-domain redirects are required, allowlist exact hosts and enforce `https`.\n\nNotes:\n\n* Express documentation calls out open redirects as dangerous user input and shows validating the host before redirecting. ([Express][1])\n* Keep Express updated: Express has had an open-redirect-related CVE affecting some versions, and upgrades are part of the mitigation posture. ([NVD][9])\n\n---\n\n### EXPRESS-HEADERS-001: Use Helmet (or equivalent) to set essential security headers\n\nSeverity: Medium\n\nRequired:\n\n* SHOULD use `helmet()` to set common security headers.\n* SHOULD configure CSP realistically (avoid `unsafe-inline` where possible) for pages that render user-influenced content.\n* SHOULD set `X-Content-Type-Options: nosniff`, clickjacking defenses (`X-Frame-Options` or CSP `frame-ancestors`), and appropriate referrer policy.\n\nNOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n\nInsecure patterns:\n\n* No security headers set in app code and no evidence they are set at the edge.\n* CSP missing on apps that display user content.\n* Misconfigured framing headers that unintentionally allow clickjacking.\n\nDetection hints:\n\n* Search for `helmet(` usage; check if CSP is configured or disabled.\n* Search for `res.setHeader(` / `res.set(` for security header setting.\n* If not visible in app code, check nginx/CDN config; otherwise flag “verify at edge.”\n\nFix:\n\n* Add `helmet()` early in middleware order and configure:\n\n  * CSP (`contentSecurityPolicy`)\n  * Frame protections (`frameguard` or CSP `frame-ancestors`)\n  * `X-Content-Type-Options` (`noSniff`)\n\nNotes:\n\n* Express production security best practices recommend Helmet and list headers Helmet sets by default. ([Express][1])\n* OWASP HTTP Headers guidance is a useful reference when tuning policies. ([OWASP Cheat Sheet Series][10])\n\n---\n\n### EXPRESS-FINGERPRINT-001: Reduce fingerprinting by disabling `x-powered-by` and customizing error/404 responses\n\nSeverity: Low (defense-in-depth)\n\nRequired:\n\n* SHOULD disable `X-Powered-By` using `app.disable('x-powered-by')`.\n* SHOULD provide a custom 404 handler and a custom error handler to avoid distinct default responses and to control information leakage.\n\nInsecure patterns:\n\n* Default `X-Powered-By: Express` header left enabled.\n* Default Express 404/error responses in production with identifiable formatting and/or stack traces.\n\nDetection hints:\n\n* Search for `app.disable('x-powered-by')`.\n* Check middleware tail for a custom 404 (`app.use((req,res)=>...)`) and a custom error handler (`app.use((err,req,res,next)=>...)`).\n* Check if `NODE_ENV` is correctly set for production behavior (see EXPRESS-ERROR-001). ([Express][11])\n\nFix:\n\n* Add:\n\n  * `app.disable('x-powered-by')`\n  * A custom 404 handler\n  * A custom error handler that logs server-side and returns generic messages client-side\n\nNotes:\n\n* Express docs explicitly recommend disabling `x-powered-by` and adding your own not-found and error handlers. ([Express][1])\n\n---\n\n### EXPRESS-COOKIE-001: Cookies must use secure attributes and minimal scope\n\nSeverity: Medium\n\nRequired:\n\n* MUST set cookie flags appropriately for any authentication/session cookie:\n\n  * `Secure` when HTTPS (production) IMPORTANT NOTE: Only set `Secure` in production environment if TLS is configured. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n  * `HttpOnly` for auth/session cookies\n  * `SameSite` set deliberately (`Lax` is a common baseline; `Strict` if compatible; `None` only with `Secure` and a justified cross-site need)\n* SHOULD avoid setting `domain` broadly (avoid “all subdomains” unless required).\n* SHOULD set bounded expiry appropriate to risk and UX.\n\nInsecure patterns:\n\n* Session/auth cookies without `HttpOnly`.\n* Cookies without `Secure` in production HTTPS.\n* `SameSite=None` + cookie-authenticated state-changing endpoints without CSRF protections.\n\nDetection hints:\n\n* Search for `res.cookie(`, `Set-Cookie`, `cookie: { ... }`, `express-session`, `cookie-session`.\n* Verify cookie flags in session middleware configuration.\n\nFix:\n\n* Set these attributes centrally in session/cookie middleware configuration.\n\nNotes:\n\n* Express production security guidance lists cookie security options (`secure`, `httpOnly`, etc.). ([Express][1])\n* `res.cookie()` ultimately sets `Set-Cookie` with options; defaults follow RFC 6265 behavior when options are omitted. ([Express][5])\n* OWASP session management guidance is relevant for choosing flags and lifetimes. ([OWASP Cheat Sheet Series][12])\n\n---\n\n### EXPRESS-SESS-001: Do not use the default session cookie name; avoid session fingerprinting\n\nSeverity: Low (defense-in-depth)\n\nRequired:\n\n* SHOULD override the default session cookie name (e.g., do not keep `connect.sid` when using `express-session`).\n* SHOULD use a generic name (e.g., `sessionId`) unless you have a compatibility reason.\n\nInsecure patterns:\n\n* `express-session` used with no `name:` configured (default cookie name).\n* Multiple apps on the same domain sharing a cookie name accidentally.\n\nDetection hints:\n\n* Search for `express-session` config blocks; check for `name:`.\n\nFix:\n\n* Set `name: 'sessionId'` (or similar) in `express-session` options.\n\nNotes:\n\n* Express docs explicitly recommend not using the default session cookie name to reduce fingerprinting. ([Express][1])\n\n---\n\n### EXPRESS-SESS-002: Session storage and lifecycle must be production-safe\n\nSeverity: High\n\nRequired:\n\n* MUST NOT use `MemoryStore` in production (it is not designed for production use).\n* MUST store session secrets outside source control and rotate them safely.\n* SHOULD regenerate sessions on login / privilege changes to reduce session fixation risk.\n* MUST NOT store sensitive secrets in client-readable cookie sessions.\n\nInsecure patterns:\n\n* `app.use(session({ store: new MemoryStore(), ... }))` or missing store (defaults to MemoryStore).\n* Hard-coded for example: `secret: 'keyboard cat'` / `secret: 's3Cur3'` in repo.\n* Using `cookie-session` to store access tokens, refresh tokens, or PII.\n\nDetection hints:\n\n* Search for `express-session` and look for `MemoryStore` usage or missing `store`.\n* Search for `secret:` in session config and check if it’s hard-coded.\n* Look for `req.session = ...` patterns and whether sensitive data is stored.\n\nFix:\n\n* Use a production session store (Redis, database-backed, etc.).\n* Load secrets from environment/secret manager.\n* On login: `req.session.regenerate(...)` or equivalent flow with safe privilege re-binding.\n\nNotes:\n\n* `express-session` explicitly warns that `MemoryStore` is not designed for production. ([Express][1])\n* `express-session` documents rotating secrets and session regeneration to guard against fixation. ([Express][1])\n* Express notes that cookie-backed sessions serialize data into the cookie and that cookie data is visible to the client; keep it small and non-secret. ([Express][1])\n\n---\n\n### EXPRESS-CSRF-001: Cookie-authenticated state-changing requests MUST be CSRF-protected\n\nSeverity: High\n\n- IMPORTANT NOTE: If cookies are not being used for auth (ie auth is via Authentication header or other passed token), then there is no CSRF risk.\n\nRequired:\n\n* MUST protect all state-changing endpoints (POST/PUT/PATCH/DELETE) that rely on cookies for authentication.\n* SHOULD use a well-understood CSRF mitigation (token-based is the typical baseline).\n* MAY add defense-in-depth: Origin/Referer validation, Fetch Metadata enforcement, SameSite cookies, custom header requirements for XHR/fetch—**but do not treat these as a full replacement** unless explicitly designed and justified.\n* MUST use at a minimum require a custom HTTP header if form based CRSF tokens are not practical, as this is the second strongest method.\n\nIMPORTANT NOTE:\n\n* If authentication is done via `Authorization: Bearer ...` headers (and not cookies), classic browser CSRF is typically not applicable;\n\nInsecure patterns:\n\n* Cookie-authenticated endpoints that change state with no CSRF protection.\n* Using GET for state-changing actions (amplifies CSRF risk).\n* “CSRF protection” that only checks a user-controlled field.\n\nDetection hints:\n\n* Enumerate routes with methods other than GET/HEAD and identify whether cookies gate auth.\n* Look for presence/absence of CSRF middleware and token checks.\n* Check JSON APIs too, not only HTML forms.\n\nFix:\n\n* Implement CSRF tokens for cookie-authenticated flows.\n* Add Origin/Referer checks where feasible, and ensure SameSite is set appropriately.\n\nNotes:\n\n* OWASP CSRF guidance and OWASP Node.js guidance both recommend anti-CSRF tokens as a standard control for web apps. ([OWASP Cheat Sheet Series][3])\n\n---\n\n### EXPRESS-CORS-001: CORS must be explicit and least-privilege\n\nSeverity: Medium (High if misconfigured with credentials)\n\nRequired:\n\n* If CORS is not needed, MUST keep it disabled.\n* If CORS is needed:\n\n  * MUST allowlist trusted origins (do not reflect arbitrary `Origin` without validation).\n  * MUST NOT combine broad origins with credentialed cookies (`Access-Control-Allow-Credentials: true`).\n  * SHOULD restrict methods, headers, and exposed headers to what’s required.\n\nInsecure patterns:\n\n* `Access-Control-Allow-Origin: *` with `Access-Control-Allow-Credentials: true`.\n* Reflecting `Origin` for all requests without allowlist validation.\n* Applying permissive CORS middleware globally when only a subset needs cross-origin access.\n\nDetection hints:\n\n* Search for `cors(`, `Access-Control-Allow-Origin`, `Access-Control-Allow-Credentials`.\n* Inspect whether cookies are used for auth on endpoints exposed cross-origin.\n\nFix:\n\n* Implement strict origin allowlist and ensure credentialed requests only for intended origins.\n* Consider splitting CORS config per route group rather than global.\n\nNotes:\n\n* OWASP HTTP header guidance covers security implications of response headers, including those that affect browser behavior; use it as a reference when reviewing header posture. ([OWASP Cheat Sheet Series][10])\n\n---\n\n### EXPRESS-PROXY-001: Reverse proxy trust (`trust proxy`) must be configured correctly\n\nSeverity: Medium (High if using IP based authentication)\n\nRequired:\n\n* If behind a reverse proxy/LB, MUST configure `app.set('trust proxy', ...)` to match the real proxy chain.\n* MUST NOT blindly set `trust proxy = true` unless you fully control the proxy behavior and header rewriting.\n* MUST ensure the last trusted proxy overwrites/removes `X-Forwarded-For`, `X-Forwarded-Host`, and `X-Forwarded-Proto` so clients cannot spoof them.\n\nInsecure patterns:\n\n* `app.set('trust proxy', true)` in an app directly exposed to the internet or behind unknown proxies.\n* Using `req.ip`, `req.protocol`, `req.hostname` for security decisions without correct proxy trust configuration.\n* Rate limiting keyed by `req.ip` with spoofable forwarded headers.\n\nDetection hints:\n\n* Search for `app.set('trust proxy'`.\n* Check infra docs (nginx/LB) for header rewriting behavior.\n* Identify any security logic using `req.ip`, `req.ips`, `req.protocol`, `req.hostname`.\n\nFix:\n\n* Set `trust proxy` to a hop count, explicit IP/subnet list, or a custom function matching your network.\n* Ensure proxies overwrite forwarded headers.\n\nNotes:\n\n* Express explicitly warns that when `trust proxy` is `true`, the client IP is derived from `X-Forwarded-For`, and if proxies don’t overwrite forwarded headers, the client can provide any value. It also describes that enabling trust proxy impacts `req.hostname` and `req.protocol` derived from forwarded headers. ([Express][2])\n\n---\n\n### EXPRESS-BODY-001: Request body size and parsing limits MUST be set appropriately\n\nSeverity: Low\n\nRequired:\n\n* SHOULD set explicit body size limits for:\n\n  * `express.json({ limit })`\n  * `express.urlencoded({ limit, parameterLimit, depth })`\n* SHOULD only enable the parsers you need; do not parse large bodies by default for all routes.\n* SHOULD enforce additional limits at the reverse proxy / gateway level.\n\nInsecure patterns:\n\n* No explicit body limits (accepting arbitrarily large JSON/urlencoded).\n* Global parsers applied to all routes when only some need bodies.\n* `parameterLimit` very high without justification (DoS potential).\n\nDetection hints:\n\n* Search for `express.json(` and confirm `limit` is set (or consciously accepted).\n* Search for `express.urlencoded(` and inspect `limit`, `parameterLimit`, and `depth`.\n* Review upload/webhook endpoints for special parsing needs.\n\nFix:\n\n* Configure parsers with conservative defaults and override per route group when needed.\n\nNotes:\n\n* Express documents `express.json` options (including `limit`, defaulting to 100kb) and explicitly notes `req.body` is untrusted and should be validated. ([Express][5])\n* Express documents `express.urlencoded` options including `limit`, `parameterLimit`, and `depth`. ([Express][5])\n* OWASP Node.js guidance also recommends setting request size limits. ([OWASP Cheat Sheet Series][8])\n\n---\n\n### EXPRESS-INPUT-002: Prevent HTTP Parameter Pollution and type confusion in `req.query`\n\nSeverity: Medium\n\nRequired:\n\n* MUST treat `req.query` values as potentially multi-valued (array/object), depending on query parsing.\n* SHOULD reject ambiguous multi-valued parameters for security-sensitive fields (e.g., `role`, `isAdmin`, `redirect`, `amount`, `userId`).\n* SHOULD consider explicit parsing or dedicated middleware if parameter pollution is a concern.\n\nInsecure patterns:\n\n* `if (req.query.admin) { ... }` without type checks (arrays/objects may coerce truthy).\n* Passing `req.query` directly into ORM/NoSQL query objects.\n\nDetection hints:\n\n* Search for security-sensitive comparisons on `req.query.*` without type enforcement.\n* Look for code that assumes query params are strings.\n\nFix:\n\n* Validate shape: enforce string-only for certain params and reject arrays/objects.\n* Normalize query parsing settings (simple vs extended) where applicable and documented.\n\nNotes:\n\n* OWASP Node.js cheat sheet explicitly highlights that Express query parsing can produce strings, arrays, or objects and recommends preventing HTTP Parameter Pollution. ([OWASP Cheat Sheet Series][8])\n\n---\n\n### EXPRESS-XSS-001: Prevent reflected/stored XSS in HTML responses and templating\n\nSeverity: High\n\nRequired:\n\n* MUST escape untrusted content in HTML output (templates should auto-escape by default; do not bypass).\n* MUST NOT inject untrusted strings into HTML without escaping/sanitization.\n* SHOULD set CSP (via Helmet) for apps rendering user-controlled content.\n* SHOULD keep `res.locals` free of user-controlled input intended for templates unless it is validated/escaped.\n\nInsecure patterns:\n\n* `res.send(\"<div>\" + req.query.q + \"</div>\")`\n* Passing untrusted HTML through “safe” template flags/filters.\n* Writing untrusted strings into `res.locals` and then rendering without escaping.\n\nDetection hints:\n\n* Search for `res.send(` with strings containing user input.\n* Search for template “safe” flags (engine-specific) and trace data origin.\n* Search for assignments to `res.locals` and whether they might contain untrusted data.\n\nFix:\n\n* Use a template engine with autoescaping; pass only validated data.\n* For rich text that must contain HTML, use a trusted sanitizer and an allowlist policy.\n* Add CSP with realistic directives.\n\nNotes:\n\n* Express API docs explicitly warn that `res.locals` “should not contain user-controlled input” and is often used to expose things like CSRF tokens to templates. ([Express][5])\n* OWASP XSS prevention guidance provides standard output-encoding and policy recommendations. ([OWASP Cheat Sheet Series][4])\n* Helmet can mitigate some XSS classes via headers such as CSP. ([Express][1])\n\n---\n\n### EXPRESS-TEMPLATE-001: Never render untrusted templates or template paths (SSTI / LFI risk)\n\nSeverity: Critical (if you can prove template strings/paths are user/attacker-controlled)\n\nRequired:\n\n* MUST NOT render templates whose contents or template path/name is influenced by untrusted input.\n* MUST NOT load templates from user-controlled filesystem locations.\n* SHOULD treat “email template editors”, “theme engines”, and “CMS-like template storage” as high-risk designs requiring sandboxing and isolation.\n\nInsecure patterns:\n\n* `res.render(req.query.view, data)` where `view` is not allowlisted.\n* Rendering a template from a string that includes user input (engine-specific).\n* Loading templates from uploads directories.\n\nDetection hints:\n\n* Search for `res.render(` where the first argument is derived from request/DB without allowlist.\n* Search for template compilation APIs (engine-specific) fed by user content.\n\nFix:\n\n* Use allowlisted template names and a fixed templates directory.\n* If user-defined templates are required, implement strict sandboxing and isolate execution.\n\nNotes:\n\n* Express’s template system depends on the chosen engine; assume unsafe if user input influences template selection or source.\n\n---\n\n### EXPRESS-FILES-001: Prevent path traversal and unsafe file serving (sendFile/download)\n\nSeverity: High\n\nRequired:\n\n* MUST NOT pass user-controlled filesystem paths directly to `res.sendFile()` / `res.download()` / filesystem APIs.\n* SHOULD use `res.sendFile` with a fixed `root` and strict options (e.g., deny dotfiles) when serving user-selected files from a directory.\n* MUST enforce authorization checks before serving user-specific files.\n\nInsecure patterns:\n\n* `res.sendFile(req.query.path)` or `res.download(req.params.file)` with no root restriction.\n* File-serving routes that accept `..` segments, encoded traversal, or absolute paths.\n\nDetection hints:\n\n* Search for `res.sendFile(` and trace the `path` argument origin.\n* Search for `res.download(` and trace the `path` argument origin.\n* Look for `fs.readFile`/`createReadStream` on paths derived from requests.\n\nFix:\n\n* Use an identifier-to-path mapping stored server-side (DB), not raw paths from clients.\n* Use `root: <trusted_base_dir>` and `dotfiles: 'deny'` where appropriate; validate the filename component strictly.\n\nNotes:\n\n* Express’s `res.sendFile` docs show using a `root` option and `dotfiles: 'deny'` as part of a safe serving configuration. ([Express][5])\n* `res.download` transfers the file as an attachment, but you still must control/validate the underlying `path`. ([Express][5])\n\n---\n\n### EXPRESS-STATIC-001: Harden `express.static` / serve-static and never serve untrusted uploads as active content\n\nSeverity: Medium (if serving untrusted user files if there are not robust limits tot eh file extensions)\n\nRequired:\n\n* MUST NOT serve user uploads from a public static directory as active content (especially HTML/JS/SVG) unless explicitly intended and sandboxed. If sure that the content is inactive (png, jpg, other images etc) then it may be safe. It may be good to validate image file extensions are allow-listed before serving them.\n* SHOULD configure static serving to:\n\n  * deny/ignore dotfiles\n  * avoid unintended directory indexes if not needed\n  * apply appropriate cache controls for immutable assets\n\nInsecure patterns:\n\n* `app.use(express.static('uploads'))` where users can upload arbitrary files.\n* Serving uploaded HTML or SVG inline from the same origin as the app.\n\nDetection hints:\n\n* Search for `express.static(` and identify served directories.\n* Compare served directories with upload storage locations.\n* Check for `dotfiles` and `index` options in static middleware.\n\nFix:\n\n* Store uploads outside any static web root and serve via controlled routes that set safe `Content-Type` and `Content-Disposition: attachment` when appropriate.\n* Configure `express.static(root, { dotfiles: 'deny'|'ignore', index: false (if desired) })`.\n\nNotes:\n\n* Express documents `express.static` options, including `dotfiles` behavior and `index`. ([Express][5])\n\n---\n\n### EXPRESS-UPLOAD-001: File uploads must be validated, stored safely, and served safely\n\nSeverity: Low - Medium\n\nRequired:\n\n* SHOULD enforce upload size limits (app + edge).\n* MUST validate file type using allowlists and content checks (not only filename extension).\n* MUST store uploads outside executable/static roots when possible.\n* SHOULD generate server-side filenames (random IDs); do not trust original names.\n* MUST serve potentially active formats safely (download attachment) unless explicitly intended.\n\nInsecure patterns:\n\n* Accepting arbitrary file types and serving them back inline.\n* Using `file.originalname` as the storage path.\n* Missing size/type validation.\n\nDetection hints:\n\n* Look for multer/busboy/formidable usage and check for `limits`.\n* Check where uploaded files are written and how they are served.\n* Check whether uploads end up under `public/` or any `express.static` root.\n\nFix:\n\n* Implement allowlist validation + safe storage + safe serving, per OWASP upload guidance.\n\nNotes:\n\n* OWASP File Upload guidance covers allowlists, content validation, storage, and safe serving patterns. ([OWASP Cheat Sheet Series][13])\n\n---\n\n### EXPRESS-INJECT-001: Prevent SQL injection (use parameterized queries / ORM)\n\nSeverity: High\n\nRequired:\n\n* MUST use parameterized queries or an ORM/query builder that parameterizes under the hood.\n* MUST NOT build SQL via string concatenation/template literals with untrusted input.\n\nInsecure patterns:\n\n* ``db.query(`SELECT * FROM users WHERE id = ${req.query.id}`)``\n* `\"SELECT ... WHERE name = '\" + req.body.name + \"'\"`\n\nDetection hints:\n\n* Grep for `SELECT`, `INSERT`, `UPDATE`, `DELETE` strings in JS/TS.\n* Trace untrusted input into `.query(...)`, `.execute(...)`, or raw SQL APIs.\n\nFix:\n\n* Replace with parameterized queries (placeholders) or ORM query APIs.\n* Validate types (e.g., integer IDs) before querying.\n\nNotes:\n\n* OWASP SQL injection prevention guidance strongly favors parameterized queries. ([OWASP Cheat Sheet Series][6])\n\n---\n\n### EXPRESS-INJECT-002: Prevent NoSQL injection / operator injection (Mongo-style)\n\nSeverity: High (app-dependent)\n\nRequired:\n\n* MUST validate types and schemas for any query object built from untrusted input.\n* MUST prevent operator injection (e.g., `$ne`, `$gt`, `$where`) if user input is merged into query objects.\n* SHOULD consider defensive libraries/middleware when appropriate.\n\nInsecure patterns:\n\n* `collection.find(req.body)` where the body is attacker-controlled.\n* Merging `req.query`/`req.body` into Mongo queries without schema validation.\n\nDetection hints:\n\n* Search for `find(`, `findOne(`, `aggregate(` calls where argument is request-derived.\n* Check for patterns like `{ ...req.query }` or `Object.assign(query, req.body)`.\n\nFix:\n\n* Use schema validation at boundary; explicitly construct query objects from validated fields only.\n\nNotes:\n\n* OWASP Node.js cheat sheet discusses input validation and mentions Node ecosystem modules commonly used for sanitization in NoSQL contexts. ([OWASP Cheat Sheet Series][8])\n\n---\n\n### EXPRESS-CMD-001: Prevent OS command injection (child_process)\n\nSeverity: Critical to High (depends on exposure), please prove it is user/attacker controlled\n\nRequired:\n\n* MUST avoid executing shell commands with untrusted input.\n* If subprocess is necessary:\n\n  * MUST avoid `exec()` / `execSync()` with attacker-influenced strings\n  * MUST NOT use `shell: true` with attacker-influenced data\n  * SHOULD use `spawn()` with an argument array and strict allowlists. Ensure the executable is hardcoded or allow-listed, do not use a user supplied command name.\n  * SHOULD place user-controlled values after `--` when supported by the subcommand to avoid flag injection\n\nInsecure patterns:\n\n* `exec(req.query.cmd)`\n* `exec(`convert ${userPath} ...`)`\n* `spawn('sh', ['-c', userString])`\n* `spawn(userString, ['foo'])`\n\nDetection hints:\n\n* Search for `child_process`, `exec(`, `execSync(`, `spawn(`, `fork(`.\n* Trace request/DB data into command construction.\n\nFix:\n\n* If possible, write the functionality in javascript or use a library instead of subprocess.\n* If unavoidable, hard-code command and strictly allowlist parameters.\n\nNotes:\n\n* OWASP OS command injection defense guidance covers avoid-shell and allowlist patterns. ([OWASP Cheat Sheet Series][14])\n\n---\n\n### EXPRESS-SSRF-001: Prevent server-side request forgery (SSRF) in outbound HTTP\n\nSeverity: Medium (High in cloud/LAN deployments)\n\nNOTE: This is mostly only applicable to apps which will be deployed in a cloud/LAN setup or have other http services on the same box. Sometimes the feature requires this functionality unavoidably (webhooks).\n\nRequired:\n\n* MUST treat outbound requests to user-provided URLs as high risk if there are other reachable private http endpoints.\n* SHOULD validate and restrict destinations (allowlist hosts/domains) for any user-influenced URL fetch.\n* SHOULD block access to:\n\n  * localhost / private IP ranges / link-local\n  * cloud metadata endpoints\n* MUST allow only `http`/`https` for URL fetch features (to avoid schemas such as `file:`,`javascript:`)\n* SHOULD set timeouts and restrict redirects.\n\nInsecure patterns:\n\n* `fetch(req.query.url)`\n* “URL preview” / “import from URL” endpoints that accept arbitrary URLs.\n\nDetection hints:\n\n* Search for `fetch(`, `axios(`, `got(`, `request(`, `node-fetch` usage where URL originates from users/DB.\n* Review webhook testers, previewers, image fetchers.\n\nFix:\n\n* Enforce scheme allowlist, host allowlist, DNS/IP resolution checks, timeouts, and redirect policy.\n* Consider network egress controls at infrastructure level.\n\nNotes:\n\n* OWASP SSRF prevention guidance provides standard controls and common pitfalls. ([OWASP Cheat Sheet Series][7])\n\n---\n\n### EXPRESS-ERROR-001: Error handling MUST not leak sensitive details in production\n\nSeverity: Low\n\nRequired:\n\n* SHOULD define a centralized error handler (`app.use((err, req, res, next) => ...)`) at the end of middleware.\n* MUST avoid returning stack traces, internal error messages, or secrets to clients in production.\n* SHOULD log errors server-side with appropriate redaction.\n* SHOULD ensure the app runs with production settings so default behavior doesn’t leak details.\n* MUST avoid logging or returning sensitive information such as secrets, env vars, sessions, cookies in error messages in production.\n\nInsecure patterns:\n\n* Returning `err.stack` to clients.\n* Using dev-only error middleware in production.\n* `NODE_ENV` left as development, causing verbose error responses.\n\nDetection hints:\n\n* Verify there is a final error-handling middleware.\n* Search for `res.status(500).send(err)` or similar.\n* Check production environment variables and startup scripts.\n\nFix:\n\n* Add a production-safe error handler that returns generic messages and logs details internally.\n* Ensure environment is configured for production behavior.\n\nNotes:\n\n* Express production security guidance recommends custom error handling. ([Express][1])\n* Express error handling docs describe the default error handler behavior and how production mode affects what is exposed. ([Express][11])\n\n---\n\n### EXPRESS-AUTH-001: Prevent brute-force attacks against authorization endpoints\n\nSeverity: Medium\n\nNOTE: This is highly application specific and while it is good to bring to the attention of the user, it is hard to fix without additional complex configurations. Prefer to inform the user and if they request you to help implement a solution, help walk them through possible solutions.\n\nRequired:\n\n* SHOULD protect login/auth endpoints against brute forcing.\n* SHOULD rate-limit by:\n\n  1. consecutive failed attempts per username+IP\n  2. failed attempts per IP over a time window\n\nInsecure patterns:\n\n* Unlimited login attempts.\n\nDetection hints:\n\n* Identify all auth endpoints and check for rate limiting/throttling.\n* Search for `rate-limiter-flexible`, `express-rate-limit`, or gateway policies.\n\nFix:\n\n* Implement rate-limiting/throttling (app or edge). Express docs point to `rate-limiter-flexible` as a tool for this approach. ([Express][1])\n\nNotes:\n\n* OWASP Node.js cheat sheet also recommends precautions against brute forcing. ([OWASP Cheat Sheet Series][8])\n\n---\n\n### EXPRESS-DEPS-001: Dependency and patch hygiene (Express + Node + critical middleware)\n\nSeverity: Medium / Low\n\nNOTE: `npm audit` often returns a large number of insignificant \"vulnerabilities\" which do not actually matter. You should only focus on Express or other extremely critical packages, ignoring ones listed in dev tools, bundlers, etc.\n\nDo not upgrade packages without concent from the user. This may break existing code in unexpected ways. Instead, inform them of the outdated packages.\n\nRequired:\n\n* MUST keep Express on a maintained version line (avoid EOL major versions).\n* MAY use `npm audit` in CI and during maintenance work.\n* SHOULD pin dependencies via lockfiles and review major updates carefully.\n\nInsecure patterns:\n\n* Running EOL Express versions (e.g., very old major lines).\n* Ignoring `npm audit` findings without triage.\n* Unpinned dependency ranges that auto-upgrade into insecure versions.\n\nDetection hints:\n\n* Check `package.json` and lockfiles for `express` version and other critical middleware versions.\n* Inspect CI pipelines for `npm audit`/SCA steps.\n\nFix:\n\n* Upgrade to latest stable Express and apply patches.\n* Add automated dependency scanning and upgrade process.\n\nNotes:\n\n* Express production security guidance emphasizes that dependency vulnerabilities can compromise the app, and recommends `npm audit`. ([Express][1])\n* Track security issues affecting Express versions (including known open-redirect-related CVEs). ([NVD][9])\n\n---\n\n### EXPRESS-DOS-001: Configure DoS protections (timeouts, limits, reverse proxy)\n\nSeverity: Low\n\nNOTE: It may be hard to tell from the provided application context if the application runs behind a reverse proxy. You can inform the user or recommend one, but do not attempt to configure one without them initiating it. This is highly deployment dependant.\n\nRequired:\n\n* SHOULD use a reverse proxy to provide caching, load balancing, and filtering controls when feasible.\n* MAY configure server/proxy timeouts and connection limits to reduce exposure to Slowloris and similar DoS patterns.\n* MUST ensure server/socket errors are handled so malformed connections do not crash the process. (Express should handle exceptions, but there are edgecases)\n\nInsecure patterns:\n\n* No reverse proxy in front of a public Node server, with defaults everywhere.\n* Missing error handlers on server/socket objects.\n* Extremely permissive timeouts and unlimited body sizes.\n\nDetection hints:\n\n* Inspect server creation (`http.createServer`, `https.createServer`) and whether timeouts are set.\n* Check proxy/gateway config for timeouts and max body size.\n\nFix:\n\n* Explain how to configure reverse proxy and timeouts, set request size limits\n* add robust error handling middleware\n\nNotes:\n\n* Node’s security guidance for HTTP DoS discusses using reverse proxies and correctly configuring server timeouts. ([Node.js][15])\n\n---\n\n### EXPRESS-NODE-INSPECT-001: Do not expose the Node inspector in production\n\nSeverity: Critical\n\nNOTE: Ensure that this detection is actually in the production path, and not just being used for local debugging.\n\nRequired:\n\n* MUST NOT run Node with `--inspect` (especially bound to non-loopback) in production.\n* MUST ensure `NODE_OPTIONS` or startup scripts do not enable inspector in prod.\n* SHOULD firewall/debug locally only.\n\nInsecure patterns:\n\n* `node --inspect=0.0.0.0:9229 app.js` in production.\n* Container/PM2/systemd configs enabling inspector.\n\nDetection hints:\n\n* Search for `--inspect` in Dockerfiles, Procfiles, systemd units, PM2 configs, npm scripts.\n* Check `NODE_OPTIONS`.\n\nFix:\n\n* Remove inspector flags from production start commands; restrict to local dev.\n\nNotes:\n\n* Node security guidance discusses inspector exposure risks (e.g., DNS rebinding) and recommends not running inspector in production. ([Node.js][15])\n\n---\n\n### EXPRESS-NODE-HTTP-001: Do not enable insecure HTTP parsing in production\n\nSeverity: High\n\nNOTE: Ensure that this detection is actually in the production path, and not just being used for local dev.\n\nRequired:\n\n* MUST NOT use Node’s `insecureHTTPParser` in production.\n* MAY suggest configuring front-end proxies to normalize ambiguous requests to reduce request smuggling risk.\n\nInsecure patterns:\n\n* Creating an HTTP server with `{ insecureHTTPParser: true }`.\n\nDetection hints:\n\n* Search for `insecureHTTPParser` in server creation code.\n\nFix:\n\n* Remove insecure parsing; rely on spec-compliant parsing and normalize at the edge.\n\nNotes:\n\n* Node security guidance explicitly recommends not using `insecureHTTPParser`. ([Node.js][15])\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning an Express repo, these patterns are high-signal:\n\n* TLS / transport:\n\n  * `app.listen(80` without reverse proxy mention; missing `helmet`; cookies missing `secure` ([Express][1]) (NOTE this only applies to web facing applications, internal apps likely won't have TLS)\n* Proxy trust:\n\n  * `app.set('trust proxy', true)`; logic using `req.ip`/`req.protocol`/`req.hostname` ([Express][2])\n* Security headers / fingerprinting:\n\n  * missing `helmet(`; missing `app.disable('x-powered-by')` ([Express][1])\n* Cookies / sessions:\n\n  * `express-session` with missing `store` (MemoryStore risk), hard-coded `secret:`, missing `cookie: { secure/httpOnly/sameSite }` ([Express][1])\n  * `cookie-session` storing large objects or secrets ([Express][1])\n* Body parsing limits:\n\n  * `express.json()` or `express.urlencoded()` without `limit`/`parameterLimit`/`depth` ([Express][5])\n* CSRF:\n\n  * POST/PUT/PATCH/DELETE routes using cookie auth with no CSRF tokens/origin checks ([OWASP Cheat Sheet Series][3])\n* Open redirects:\n\n  * `res.redirect(req.query.next)` or similar ([Express][1])\n* XSS / HTML output:\n\n  * `res.send(` building HTML with user input; template “safe” flags; untrusted values in `res.locals` ([Express][5])\n* File handling:\n\n  * `res.sendFile(` / `res.download(` where path originates from request; `express.static('uploads')` ([Express][5])\n* Injection:\n\n  * SQL strings + template literals into DB calls ([OWASP Cheat Sheet Series][6])\n  * `child_process.exec` / `execSync` / `shell: true` ([OWASP Cheat Sheet Series][14])\n* SSRF:\n\n  * outbound `fetch/axios/got` to user-provided URLs ([OWASP Cheat Sheet Series][7])\n* Brute force / abuse:\n\n  * auth endpoints lacking throttling; no rate limiting middleware ([Express][1])\n* Supply chain:\n\n  * outdated Express versions; no lockfiles; no `npm audit` workflow ([Express][1])\n* Node runtime hazards:\n\n  * `--inspect` in production scripts; `insecureHTTPParser` usage ([Node.js][15])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (HTML/template, SQL/NoSQL, subprocess, filesystem, redirect, outbound HTTP)\n* protective controls present (validation, allowlists, middleware, proxy config, header policies)\n* whether protections are at the edge vs in app code\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary Express documentation:\n\n* Express: Production Best Practices — Security: `https://expressjs.com/en/advanced/best-practice-security.html` ([Express][1])\n* Express: Behind Proxies (`trust proxy`): `https://expressjs.com/en/guide/behind-proxies.html` ([Express][2])\n* Express 5.x API Reference (parsers, static, sendFile, redirect, cookies): `https://expressjs.com/en/5x/api.html` ([Express][5])\n* Express: Error Handling: `https://expressjs.com/en/guide/error-handling.html` ([Express][11])\n\nSession middleware documentation:\n\n* express-session docs (cookie flags, secret rotation, fixation mitigation, MemoryStore warning): `https://expressjs.com/en/resources/middleware/session.html` ([Express][1])\n\nNode.js and npm official references:\n\n* Node.js — Security Best Practices (DoS, proxy guidance, inspector risks, request smuggling notes): `https://nodejs.org/en/learn/getting-started/security-best-practices` ([Node.js][15])\n* npm Docs — `npm audit`: `https://docs.npmjs.com/cli/v9/commands/npm-audit/` ([npm Docs][16])\n\nOWASP Cheat Sheet Series:\n\n* Session Management: `https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][12])\n* CSRF Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][3])\n* XSS Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][4])\n* Input Validation: `https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][17])\n* SQL Injection Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][6])\n* OS Command Injection Defense: `https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][14])\n* SSRF Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][7])\n* File Upload: `https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][13])\n* Unvalidated Redirects: `https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][18])\n* HTTP Headers: `https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][10])\n\nVersioning / advisories:\n\n* Express package version (npm): `https://www.npmjs.com/package/express`\n* Express open redirect advisory (CVE): `https://nvd.nist.gov/vuln/detail/CVE-2024-29041` ([NVD][9])\n\n[1]: https://expressjs.com/en/advanced/best-practice-security.html \"Security Best Practices for Express in Production\"\n[2]: https://expressjs.com/en/guide/behind-proxies.html \"Express behind proxies\"\n[3]: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html \"Cross-Site Request Forgery Prevention - OWASP Cheat Sheet Series\"\n[4]: https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html \"Cross Site Scripting Prevention - OWASP Cheat Sheet Series\"\n[5]: https://expressjs.com/en/5x/api.html \"Express 5.x - API Reference\"\n[6]: https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html \"SQL Injection Prevention - OWASP Cheat Sheet Series\"\n[7]: https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html \"Server Side Request Forgery Prevention - OWASP Cheat Sheet Series\"\n[8]: https://cheatsheetseries.owasp.org/cheatsheets/Nodejs_Security_Cheat_Sheet.html \"Nodejs Security - OWASP Cheat Sheet Series\"\n[9]: https://nvd.nist.gov/vuln/detail/cve-2024-29041?utm_source=chatgpt.com \"CVE-2024-29041 Detail - NVD\"\n[10]: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html \"HTTP Headers - OWASP Cheat Sheet Series\"\n[11]: https://expressjs.com/en/guide/error-handling.html \"Express error handling\"\n[12]: https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html \"Session Management - OWASP Cheat Sheet Series\"\n[13]: https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html \"File Upload - OWASP Cheat Sheet Series\"\n[14]: https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html \"OS Command Injection Defense - OWASP Cheat Sheet Series\"\n[15]: https://nodejs.org/en/learn/getting-started/security-best-practices \"Node.js — Security Best Practices\"\n[16]: https://docs.npmjs.com/cli/v9/commands/npm-audit/ \"npm-audit | npm Docs\"\n[17]: https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html \"Input Validation - OWASP Cheat Sheet Series\"\n[18]: https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html \"Unvalidated Redirects and Forwards - OWASP Cheat Sheet Series\"\n","core/skills/builtin/security-best-practices/references/javascript-general-web-frontend-security.md":"# Frontend JavaScript/TypeScript Web Security Spec (Vanilla Browser JS/TS, Modern Browsers)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new frontend JavaScript/TypeScript (no specific framework assumed).\n2. **Security review / vulnerability hunting** in existing frontend code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, hard-code, or commit secrets (API keys intended to be secret, private keys, passwords, OAuth refresh tokens, session tokens, cookies).\n  Notes:\n\n  * Frontend code is inherently observable by end users. If a value must remain secret, it must not be in browser-delivered code.\n  * If the project uses “public” keys (e.g., publishable analytics keys), they MUST be treated as non-secret and scoped accordingly.\n\n* MUST NOT “fix” security by disabling protections (e.g., weakening CSP with `unsafe-inline`/`unsafe-eval` without justification, removing origin checks for `postMessage`, switching to `innerHTML` for convenience, accepting arbitrary redirects/URLs, or turning off sanitization).\n\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and relevant HTML/CSP/config values that justify the claim.\n\n* MUST treat uncertainty honestly:\n\n  * Security headers (CSP, frame-ancestors, etc.) might be set by server/edge/CDN rather than in repo code. If not visible, report as “not visible here; verify at runtime/edge config.” (Also note that `<meta http-equiv=...>` only simulates a subset of headers; don’t assume other security headers exist just because a meta tag exists.) ([MDN Web Docs][1])\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new frontend JS/TS code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default browser APIs and proven libraries over custom security code (especially for HTML sanitization).\n* MUST avoid introducing new risky sinks (DOM XSS injection sinks like `innerHTML`, navigation to `javascript:` URLs, dynamic code execution via `eval`/`Function`, unsafe `postMessage`, unsafe third-party script loading, etc.). ([OWASP Cheat Sheet Series][2])\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a frontend repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. HTML entrypoints (`index.html`, server-rendered templates), script/style includes, and any CSP delivery (header vs meta). ([W3C][3])\n2. DOM XSS sinks (`innerHTML`, `document.write`, `insertAdjacentHTML`, event-handler attributes) and their data sources (URL params/hash, storage, postMessage, API responses). ([OWASP Cheat Sheet Series][2])\n3. Navigation/redirect handling (`window.location*`, link targets, URL allowlists) including `javascript:` URL hazards. ([MDN Web Docs][4])\n4. Cross-origin communication (`postMessage`, iframe embed patterns, sandboxing). ([MDN Web Docs][5])\n5. Storage of sensitive data (localStorage/sessionStorage) and assumptions about trust. ([OWASP Cheat Sheet Series][6])\n6. Third-party scripts / tag managers / CDNs, and integrity controls (SRI) and policy controls (CSP). ([OWASP Cheat Sheet Series][7])\n7. DOM clobbering gadgets and unsafe reliance on `window`/`document` named properties. ([OWASP Cheat Sheet Series][8])\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nExamples include:\n\n* URL-derived data: `location.href`, `location.search`, `location.hash`, `document.baseURI`, `new URLSearchParams(location.search)`, routing fragments. ([OWASP Cheat Sheet Series][2])\n* DOM content that may include user-controlled markup (comments, profiles, CMS content, markdown-to-HTML output, etc.), especially if inserted dynamically. ([OWASP Cheat Sheet Series][2])\n* `postMessage` event data (`event.data`) and metadata (`event.origin`) from other windows/frames. ([MDN Web Docs][5])\n* Browser storage: `localStorage`, `sessionStorage`, IndexedDB (contents can be attacker-influenced via XSS or local machine access; never treat as “trusted”). ([OWASP Cheat Sheet Series][6])\n* Any data returned from network calls (even if from “your API”), because it may contain stored attacker content that becomes dangerous only when inserted into the DOM. ([OWASP Cheat Sheet Series][2])\n\n### 2.2 Dangerous sink (DOM XSS / code execution sink)\n\nA sink is any API/operation that can execute script or interpret attacker-controlled strings as HTML/JS/URL in a security-sensitive way. High-signal sinks include:\n\n* HTML parsing / insertion: `innerHTML`, `outerHTML`, `insertAdjacentHTML`, `document.write`, `document.writeln`. ([OWASP Cheat Sheet Series][2])\n* Dynamic code execution: `eval`, `new Function`, `setTimeout(\"...\")`, `setInterval(\"...\")`. ([MDN Web Docs][10])\n* Navigation to script-bearing URLs (e.g., `javascript:`) via setters like `Location.href`/`window.location` (and via link `href` if attacker-controlled). ([MDN Web Docs][4])\n* Setting event handler attributes from strings, e.g. `setAttribute(\"onclick\", \"...\")`. ([OWASP Cheat Sheet Series][2])\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + function/class/module + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest baseline that prevents common frontend JS/TS security misconfigurations. Some items are “in repo” (HTML/JS) and some may live at the server/edge.\n\n### 3.1 Content Security Policy (CSP) baseline (SHOULD; MUST for high-risk apps)\n\n* SHOULD deliver CSP via HTTP response headers when possible.\n* MAY deliver CSP via an HTML `<meta http-equiv=\"Content-Security-Policy\" ...>` tag when you cannot set headers (e.g., purely static hosting constraints). ([MDN Web Docs][1])\n* If using CSP via `<meta http-equiv>`, MUST understand the limitations:\n\n  * The policy only applies to content that follows the meta element (so it must appear very early, before any scripts/resources you want governed). ([W3C][3])\n  * The following directives are **not supported** in a meta-delivered policy and will be ignored: `report-uri`, `frame-ancestors`, and `sandbox`. ([W3C][3])\n  * “Report-only” CSP cannot be set via a meta element. ([W3C][3])\n\nPractical baseline goals:\n\n* Avoid script sources `unsafe-inline` and `unsafe-eval` (they significantly weaken CSP’s value against XSS). ([MDN Web Docs][10])\n* Prefer nonce- or hash-based script policies if you need inline scripts. ([MDN Web Docs][10])\n* Consider enabling Trusted Types enforcement where feasible. ([MDN Web Docs][11])\n\n### 3.2 Third-party scripts baseline (SHOULD)\n\n* SHOULD minimize third-party script execution and treat it as equivalent privilege to first-party JS (it runs with your origin’s privileges). ([OWASP Cheat Sheet Series][7])\n* SHOULD use Subresource Integrity (SRI) for third-party scripts/styles loaded from CDNs. ([MDN Web Docs][12])\n\n### 3.3 Cross-window communication baseline (SHOULD)\n\n* SHOULD restrict `postMessage` communications to explicit origins, and validate both origin and message shape. ([MDN Web Docs][5])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### JS-XSS-001: Do not inject untrusted HTML into the DOM (avoid `innerHTML` and friends)\n\nSeverity: Critical if you can prove attacker-controlled input can reach these APIs; otherwise Medium\n\n\nRequired:\n\n* MUST treat `innerHTML`, `outerHTML`, and `insertAdjacentHTML` as dangerous sinks when their input can contain untrusted data. ([OWASP Cheat Sheet Series][2])\n* MUST prefer safe DOM APIs that do not parse HTML:\n\n  * `textContent` for text. ([OWASP Cheat Sheet Series][2])\n  * `document.createElement`, `appendChild`, `setAttribute` for non-event-handler attributes. ([OWASP Cheat Sheet Series][2])\n* If HTML insertion is truly required, SHOULD sanitize with a well-reviewed HTML sanitizer and strongly consider enforcing Trusted Types to confine usage to audited code paths. ([MDN Web Docs][11])\n\nInsecure patterns:\n\n* `el.innerHTML = userInput`\n* `el.insertAdjacentHTML('beforeend', userInput)`\n* `el.outerHTML = userInput`\n\nDetection hints:\n\n* Search for: `.innerHTML`, `.outerHTML`, `insertAdjacentHTML(`.\n* Trace the origin of inserted string: URL params/hash, postMessage, storage, API responses, DOM attributes. ([OWASP Cheat Sheet Series][2])\n\nFix:\n\n* Replace with `textContent` for plain text. ([OWASP Cheat Sheet Series][2])\n* For structured UI, build DOM nodes explicitly.\n* For “rich text” requirements:\n\n  * Sanitize using an allowlist-based sanitizer.\n  * Prefer returning safe “components” instead of arbitrary HTML strings.\n  * Use Trusted Types enforcement to ensure only `TrustedHTML` reaches sinks where supported. ([MDN Web Docs][11])\n\nMitigation:\n\n* Deploy a strict CSP and consider Trusted Types enforcement (`require-trusted-types-for 'script'`). ([MDN Web Docs][10])\n\nFalse positive notes:\n\n* If the string is provably constant or fully generated from trusted constants, it may be safe. Still prefer safer APIs.\n\n---\n\n### JS-XSS-002: Avoid `document.write` / `document.writeln` (XSS + document clobbering hazards)\n\nSeverity: Critical if you can prove attacker-controlled input can reach these APIs; otherwise Medium\n\nRequired:\n\n* MUST avoid `document.write()` and `document.writeln()` in production code (they are XSS vectors and can be abused with crafted HTML even if some browsers block injected `<script>` in certain situations). ([MDN Web Docs][13])\n* If legacy use is unavoidable, MUST ensure no untrusted input reaches these APIs and SHOULD enforce Trusted Types (`TrustedHTML`) where supported. ([MDN Web Docs][14])\n\nInsecure patterns:\n\n* `document.write(userInput)`\n* `document.writeln(getParam('q'))`\n\nDetection hints:\n\n* Search for `document.write(`, `document.writeln(`. ([OWASP Cheat Sheet Series][2])\n\nFix:\n\n* Replace with DOM manipulation (`createElement`, `appendChild`) or safe text insertion (`textContent`). ([OWASP Cheat Sheet Series][2])\n\nMitigation:\n\n* Strict CSP + Trusted Types enforcement reduces blast radius if a sink remains. ([MDN Web Docs][10])\n\n---\n\n### JS-XSS-003: Do not use string-to-code execution (`eval`, `new Function`, string timeouts)\n\nSeverity: Critical if you can prove attacker-controlled input can reach these APIs; otherwise Medium\n\nRequired:\n\n* MUST NOT pass untrusted data to:\n\n  * `eval()`\n  * `new Function(...)`\n  * `setTimeout(\"...\")` / `setInterval(\"...\")` with string arguments ([MDN Web Docs][10])\n* SHOULD avoid these APIs entirely in modern frontend code; refactor to non-eval logic. ([MDN Web Docs][10])\n* MUST NOT “fix CSP breakage” by adding `unsafe-eval` unless there is a documented, reviewed justification and compensating controls. ([MDN Web Docs][10])\n\nInsecure patterns:\n\n* `eval(userInput)`\n* `new Function(\"return \" + userInput)()`\n* `setTimeout(userInput, 0)` where userInput is a string\n\nDetection hints:\n\n* Search for `eval(`, `new Function`, `setTimeout(\"`, `setInterval(\"`.\n* Also search for construction of code strings used later.\n\nFix:\n\n* Replace dynamic code with:\n\n  * structured data + explicit branching/handlers,\n  * JSON parsing (`JSON.parse`) instead of `eval` for JSON. ([OWASP Cheat Sheet Series][2])\n\nMitigation:\n\n* CSP that blocks `eval()`-like APIs by default, and avoid `unsafe-eval`. ([MDN Web Docs][10])\n* Consider Trusted Types for controlled cases, but treat it as a hardening layer, not a license to keep eval patterns. ([MDN Web Docs][10])\n\n---\n\n### JS-XSS-004: Do not set event handler attributes from strings (e.g., `setAttribute(\"onclick\", \"...\")`)\n\nSeverity: High\n\nRequired:\n\n* MUST NOT use `setAttribute(\"on…\", string)` or similar patterns with untrusted data; this coerces strings into executable code in the event-handler context. ([OWASP Cheat Sheet Series][2])\n* SHOULD prefer `addEventListener` with function references.\n\nInsecure patterns:\n\n* `el.setAttribute(\"onclick\", userInput)`\n* `el.onclick = userControlledString` (string assignment)\n\nDetection hints:\n\n* Search for `.setAttribute(\"on`, `.onclick =`, `.onmouseover =`, etc.\n* Trace whether RHS can be influenced by URL/hash/storage/postMessage. ([OWASP Cheat Sheet Series][2])\n\nFix:\n\n* Replace with `addEventListener(\"click\", () => { ... })`.\n* If dynamic dispatch is needed, use an allowlisted mapping from identifiers to functions (no string eval). ([OWASP Cheat Sheet Series][2])\n\n---\n\n### JS-URL-001: Sanitize and allowlist URLs before navigation (especially `window.location` / `location.replace`)\n\nSeverity: Low (High if you can prove an attacker can fully control the URL)\n\nIMPORTANT: This can cause a lot of false positives. Please perform extra analysis to determine if the url is fully attacker controlled. If not fully attacker controlled, then this is informational at best.\n\nNOTE: It may be important functionality to be able to redirect to any given url. If that is the goal of the feature, then at a minimum, ensure it checks the schema even if the origin is allowed to be anything.\n\nRequired:\n\n* MUST treat any assignment to navigation targets as security-sensitive:\n\n  * `window.location = ...`\n  * `location.href = ...`\n  * `location.assign(...)`\n  * `location.replace(...)` ([MDN Web Docs][4])\n* MUST prevent navigation to `javascript:` URLs (and generally other script-bearing/active schemes), especially when input is derived from URL params, storage, or messages. ([MDN Web Docs][4]). Only allow `http:` and `https:`.\n* SHOULD validate/allowlist the destination. A safe baseline is:\n\n  * Allow only same-origin relative paths, OR\n  * Allow only a strict allowlist of origins and protocols (typically `https:` and optionally `http:` for localhost dev). ([OWASP Cheat Sheet Series][8])\n\nInsecure patterns:\n\n* `location.replace(getParam(\"next\"))`\n* `window.location = userSuppliedUrl`\n* `location.assign(window.redirectTo || \"/\")` where `redirectTo` can be clobbered or attacker-set ([OWASP Cheat Sheet Series][8])\n\nDetection hints:\n\n* Search for `window.location`, `location.href`, `location.assign`, `location.replace`.\n* Search for common redirect parameters: `next`, `returnTo`, `redirect`, `url`, `continue`.\n* Search for `javascript:` literal usage. ([MDN Web Docs][4])\n\nFix:\n\n* Parse and validate with `new URL(value, location.origin)` and then enforce:\n\n  * `url.protocol` in `{ \"https:\" }` (and only include `http:` in explicit dev-only code paths),\n  * `url.origin` equals `location.origin` for internal redirects, or in a strict allowlist for external redirects,\n  * optionally allow only specific path prefixes. ([MDN Web Docs][4])\n* If validation fails, navigate to a safe default (home/dashboard).\n\nMitigation:\n\n* Deploy strict CSP and Trusted Types enforcement to reduce the impact of DOM XSS sinks, but note that Trusted Types do not prevent every possible unsafe navigation scenario on their own. ([W3C][15])\n\nFalse positive notes:\n\nIMPORTANT: This can cause a lot of false positives. Please perform extra analysis to determine if the url is fully attacker controlled. If not fully attacker controlled, then this is informational at best.\n\n* Some apps intentionally support external redirects (SSO, payment flows). Those MUST be allowlisted and documented.\n\n---\n\n### JS-URL-002: Sanitize URLs before inserting into DOM URL contexts (`href`, `src`, etc.)\n\nSeverity: Low (High if you can prove an attacker can fully control the URL)\n\nIMPORTANT: This can cause a lot of false positives. Please perform extra analysis to determine if the url is fully attacker controlled. If not fully attacker controlled, then this is informational at best.\n\nRequired:\n\n* MUST treat setting URL-bearing DOM attributes/properties as security-sensitive, especially:\n\n  * `a.href`, `img.src`, `script.src`, `iframe.src`, `form.action`, `link.href`.\n* MUST prevent script-bearing schemes (`javascript:` and other active schemes) when values can be attacker-influenced. ([MDN Web Docs][4])\n* SHOULD prefer setting properties (e.g., `a.href = url.toString()`) after parsing and validation, rather than string concatenation.\n\nInsecure patterns:\n\n* `link.href = getParam(\"u\")`\n* `el.setAttribute(\"href\", userInput)` without validation\n* constructing URLs via concatenation with untrusted pieces\n\nDetection hints:\n\n* Search for `.href =`, `.src =`, `.action =`, `setAttribute(\"href\"`, `setAttribute(\"src\"`.\n* Search for `javascript:` / `data:` usage in URLs. ([MDN Web Docs][4])\n\nIMPORTANT: This can cause a lot of false positives. Please perform extra analysis to determine if the url is fully attacker controlled. If not fully attacker controlled, then this is informational at best.\n\nFix:\n\n* Use `new URL(...)` and validate:\n\n  * protocol allowlist\n  * avoid passing user-provided values into `<script src>` at all (treat as code execution). ([OWASP Cheat Sheet Series][8])\n\n---\n\n### JS-CSP-001: Use CSP; meta delivery is allowed\n\nSeverity: Medium to High (depends on threat model; High when handling untrusted content)\n\nNOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n\nRequired:\n\n* SHOULD deploy a CSP as a major defense-in-depth against XSS. ([MDN Web Docs][10])\n* MAY provide CSP via `<meta http-equiv=\"Content-Security-Policy\" ...>` when headers are not available. ([MDN Web Docs][1])\n* If CSP is delivered via meta, MUST:\n\n  * place it early (before scripts/resources you want governed), and\n  * not rely on unsupported directives in meta policies (`report-uri`, `frame-ancestors`, `sandbox`). ([W3C][3])\n* MUST avoid adding `unsafe-inline` as a “quick fix” for CSP issues unless explicitly required and reviewed (it defeats much of CSP’s purpose). ([MDN Web Docs][10])\n* MUST avoid adding `unsafe-eval` unless explicitly required and reviewed (it allows eval-like APIs that are commonly abused). ([MDN Web Docs][10])\n\nInsecure patterns:\n\n* No CSP present anywhere (repo HTML or server/edge) for an app that renders untrusted content.\n* CSP includes `script-src 'unsafe-inline'` and/or `script-src 'unsafe-eval'` without strong justification. ([MDN Web Docs][10])\n* CSP delivered via meta but includes `frame-ancestors` (it will be ignored in meta). ([W3C][3])\n\nDetection hints:\n\n* Search HTML for `<meta http-equiv=\"Content-Security-Policy\"`.\n* Search server/edge configs for `Content-Security-Policy` header.\n* If CSP is only in meta, check it appears before any `<script>` tags you want governed. ([W3C][3])\n\nFix:\n\n* Prefer header-delivered CSP at the server/edge.\n* If constrained to meta, keep a strong allowlist CSP and document the limitations; implement clickjacking protections (e.g., `frame-ancestors`) at the server/edge, not in meta. ([W3C][3])\n\n---\n\n### JS-CSP-002: Prefer strict CSP (nonces/hashes); avoid inline/eval patterns in code\n\nSeverity: Medium\n\nNOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n\nRequired:\n\n* SHOULD design frontend code to work under a strict CSP:\n\n  * avoid inline scripts and inline event handlers,\n  * avoid eval-like APIs (see JS-XSS-003),\n  * allow scripts via nonce or hash when needed. ([MDN Web Docs][10])\n\nInsecure patterns:\n\n* Large amounts of inline script blocks and inline `onclick=\"...\"` handlers.\n* Libraries that require `unsafe-eval`.\n\nDetection hints:\n\n* Search for `<script>` blocks with inline code, `onclick=\"`, `onload=\"`, etc.\n* Search for CSP directives containing `unsafe-inline` or `unsafe-eval`. ([MDN Web Docs][10])\n\nFix:\n\n* Move inline scripts into external JS files (same-origin).\n* Use nonces/hashes for any unavoidable inline blocks. ([MDN Web Docs][10])\n\n---\n\n### JS-TT-001: Use Trusted Types to reduce DOM XSS attack surface (where supported)\n\nSeverity: Low\n\nRequired:\n\n* SHOULD consider enabling Trusted Types enforcement with CSP `require-trusted-types-for 'script'` to make many DOM XSS sinks reject raw strings. ([MDN Web Docs][11])\n* If using Trusted Types, SHOULD also use the CSP `trusted-types` directive to restrict which policies can be created (reduces policy sprawl and improves auditability). ([MDN Web Docs][16])\n* MUST keep Trusted Types policy code small, heavily reviewed, and used as the only path to produce trusted values for sinks. ([W3C][15])\n\nInsecure patterns:\n\n* “Trusted Types enabled” but policy simply returns input unchanged (no sanitization/validation).\n* Many ad-hoc policies created across the codebase without restriction.\n* Belief that Trusted Types alone prevents all unsafe navigations or all XSS classes. (It targets DOM injection sinks; it is not a universal sandbox.) ([W3C][15])\n\nDetection hints:\n\n* Search for CSP directives: `require-trusted-types-for` and `trusted-types`.\n* Search code for `trustedTypes.createPolicy(` and inspect policy implementations. ([MDN Web Docs][11])\n\nFix:\n\n* Add a small set of well-reviewed policies (e.g., `createHTML` that sanitizes).\n* Restrict allowed policies via `trusted-types <policyName...>`.\n* Migrate sinks to require `TrustedHTML` / `TrustedScriptURL` as appropriate. ([MDN Web Docs][11])\n\n---\n\n### JS-MSG-001: `postMessage` must use strict origin validation and explicit targetOrigin\n\nSeverity: Medium (High if dangerous behavior can be triggered via postMessage)\n\nRequired:\n\n* When sending messages, MUST set an explicit `targetOrigin` (not `*`) to avoid sending data to an unexpected origin after redirects or window origin changes. ([MDN Web Docs][5])\n* When receiving messages, MUST:\n\n  * Validate `event.origin` exactly against an allowlist of expected origins (no substring matching). ([OWASP Cheat Sheet Series][6])\n  * Consider validating `event.source` (expected window reference) when applicable. ([MDN Web Docs][5])\n  * Validate `event.data` structure (schema/shape) and treat it purely as data (never evaluate it as code and never insert into DOM with `innerHTML`). ([OWASP Cheat Sheet Series][6])\n\nInsecure patterns:\n\n* `otherWindow.postMessage(payload, \"*\")`\n* `window.addEventListener(\"message\", (e) => { doSomething(e.data) })` with no `origin` check\n* `if (e.origin.includes(\"trusted.com\"))` (substring checks)\n* `el.innerHTML = e.data` ([OWASP Cheat Sheet Series][6])\n\nDetection hints:\n\n* Search for `postMessage(`, `addEventListener(\"message\"`, `onmessage =`.\n* Audit all handlers for explicit allowlist checks on `event.origin`. ([OWASP Cheat Sheet Series][6])\n\nFix:\n\n* Define an allowlist:\n\n  * `const ALLOWED = new Set([\"https://app.example.com\", \"https://accounts.example.com\"]);`\n  NOTE: For ease of development, you can use the current page's origin `window.location.origin` as a safe default origin.\n* On receive:\n\n  * `if (!ALLOWED.has(event.origin)) return;`\n  * Validate `event.data` with a strict schema and reject unknown/extra fields.\n* On send:\n\n  * use the exact expected origin string as `targetOrigin`. ([OWASP Cheat Sheet Series][6])\n\nMitigation:\n\n* Combine with a strict CSP and avoid DOM sinks in message paths. ([MDN Web Docs][10])\n\n---\n\n### JS-STORAGE-001: Web Storage is not a safe place for secrets (and is attacker-influencable)\n\nSeverity: Low\n\nRequired:\n\n* MUST NOT store sensitive secrets or session identifiers in `localStorage` (or `sessionStorage`) if compromise would matter; a single XSS can exfiltrate everything in storage. ([OWASP Cheat Sheet Series][6])\n* MUST treat values read from storage as untrusted input (attackers can load malicious values into storage via XSS). ([OWASP Cheat Sheet Series][6])\n* SHOULD prefer server-set cookies with `HttpOnly` for session identifiers (JS cannot set `HttpOnly`, so avoid storing session IDs in JS-accessible storage). ([OWASP Cheat Sheet Series][6])\n* SHOULD avoid hosting multiple unrelated apps on the same origin if they rely on storage separation (storage is origin-wide). ([OWASP Cheat Sheet Series][6])\n\nInsecure patterns:\n\n* `localStorage.setItem(\"access_token\", token)`\n* `localStorage.setItem(\"session\", sessionId)`\n* Assuming `localStorage` is “trusted because same-origin.”\n\nDetection hints:\n\n* Search for `localStorage.getItem`, `localStorage.setItem`, `sessionStorage.*`.\n* Flag storage keys named `token`, `jwt`, `session`, `auth`, `refresh`. ([OWASP Cheat Sheet Series][6])\n\nFix:\n\n* Use server-managed sessions or short-lived tokens delivered and rotated securely, with careful XSS defenses (CSP/Trusted Types) and minimal JS exposure.\n* If storage must be used for non-sensitive state, keep it non-auth and validate/escape before use.\n\n---\n\n### JS-SUPPLY-001: Third-party JavaScript is a major supply-chain risk; minimize and control it\n\nSeverity: Low\n\nRequired:\n\n* MUST treat third-party JS as equivalent to first-party JS in privilege (it can execute arbitrary code in your origin and access DOM data). ([OWASP Cheat Sheet Series][7])\n* SHOULD minimize third-party scripts and prefer:\n\n  * self-hosting / script mirroring,\n  * strict CSP allowlists,\n  * SRI for any CDN-hosted scripts,\n  * ongoing monitoring for unexpected changes. ([OWASP Cheat Sheet Series][7])\n\nInsecure patterns:\n\n* Loading arbitrary remote scripts from many vendors without review.\n* Using tag managers that can dynamically inject scripts with no integrity controls.\n* Allowing scripts from broad wildcards in CSP (e.g., `script-src *`). ([MDN Web Docs][10])\n\nDetection hints:\n\n* Search HTML for `<script src=\"https://...\">` and `tag manager` snippets.\n* Search CSP `script-src` sources for wildcards or overly broad domains.\n* Search for dynamic script injection: `document.createElement(\"script\")`, `script.src = ...`, `appendChild(script)`. ([OWASP Cheat Sheet Series][8])\n\nFix:\n\n* Remove unnecessary third-party tags.\n* Self-host or mirror scripts where possible.\n* Lock down CSP `script-src` to the smallest set of trusted sources.\n* Add SRI for CDN scripts/styles. ([OWASP Cheat Sheet Series][7])\n\n---\n\n### JS-SRI-001: Use Subresource Integrity (SRI) for third-party scripts/styles\n\nSeverity: Low\n\nRequired:\n\n* SHOULD use SRI to ensure browsers only load third-party resources if they match an expected cryptographic hash. ([MDN Web Docs][12])\n* MUST update SRI hashes whenever the underlying resource changes (pin versions; avoid “latest” URLs).\n\nInsecure patterns:\n\n* `<script src=\"https://cdn.example.com/lib.js\"></script>` with no `integrity`.\n* Loading `latest` or unpinned third-party resources.\n\nDetection hints:\n\n* Search for `<script src=\"https://` and `<link rel=\"stylesheet\" href=\"https://` without `integrity=`.\n* Check whether `integrity` is present and uses strong hashes (sha256/384/512 are typical). ([MDN Web Docs][12])\n\nFix:\n\n* Add `integrity=\"sha384-...\"` (or appropriate) and ensure proper CORS mode where needed.\n* Prefer self-hosting critical libraries.\n\n---\n\n### FS-DOMC-001: Prevent DOM clobbering (avoid relying on `window`/`document` named properties)\n\nSeverity: Medium to High (can become Critical if it enables script loading or `javascript:` navigation)\n\nRequired:\n\n* MUST NOT rely on implicit global variables or `window.someName` / `document.someName` lookups that can be clobbered by injected HTML elements with matching `id`/`name`. ([OWASP Cheat Sheet Series][8])\n* MUST avoid patterns like `let x = window.redirectTo || \"/safe\"; location.assign(x);` where `redirectTo` could be clobbered to an `<a>` element whose `href` is attacker-controlled (including `javascript:`). ([OWASP Cheat Sheet Series][8])\n* SHOULD use explicit variable declarations, local scope, and explicit DOM queries (`getElementById`) rather than named property access. ([OWASP Cheat Sheet Series][8])\n* If the app inserts user-controlled markup (even sanitized), SHOULD ensure sanitization strategies consider `id`/`name` collisions. ([OWASP Cheat Sheet Series][8])\n\nInsecure patterns:\n\n* `const cfg = window.config || {};` used for security-sensitive URLs.\n* `const redirect = window.redirectTo || \"/\"; location.assign(redirect);` ([OWASP Cheat Sheet Series][8])\n* Loading scripts from `window.*` config values without strict validation.\n\nDetection hints:\n\n* Search for `window.` and `document.` used as config stores (especially `||` fallback patterns).\n* Search for usage of `location.assign/replace` with variables that come from `window`/`document` properties.\n* Search for dynamic script creation (`createElement('script')`) where `.src` comes from a non-local variable. ([OWASP Cheat Sheet Series][8])\n\nFix:\n\n* Store config in module-scoped constants (not on `window`/`document`) and pass it explicitly.\n* Validate any URL-like config with protocol/origin allowlists (see FEJS-URL-001). ([OWASP Cheat Sheet Series][8])\n* Consider hardening: sanitization, CSP, and (in limited cases) freezing sensitive objects, but treat these as defense-in-depth, not a substitute for safe coding patterns. ([OWASP Cheat Sheet Series][8])\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* DOM XSS sinks:\n\n  * `.innerHTML`, `.outerHTML`, `insertAdjacentHTML(`\n  * `document.write(`, `document.writeln(` ([OWASP Cheat Sheet Series][2])\n\n* Dangerous navigation / URL sinks:\n\n  * `window.location`, `location.href`, `location.assign`, `location.replace`\n  * `javascript:` literals (and other suspicious schemes like `data:text/html`) ([MDN Web Docs][4])\n\n* String-to-code execution:\n\n  * `eval(`, `new Function`, `setTimeout(\"`, `setInterval(\"` ([MDN Web Docs][10])\n\n* Event-handler string injection:\n\n  * `.setAttribute(\"on`, `.onclick =`, `.onload =` with strings ([OWASP Cheat Sheet Series][2])\n\n* `postMessage`:\n\n  * `postMessage(` with `\"*\"` as targetOrigin\n  * `addEventListener(\"message\"` without strict `event.origin` allowlist checks ([MDN Web Docs][5])\n\n* Storage:\n\n  * `localStorage.setItem(` / `getItem(`, `sessionStorage.*`\n  * keys containing `token`, `jwt`, `session`, `auth`, `refresh` ([OWASP Cheat Sheet Series][6])\n\n* CSP and related:\n\n  * `Content-Security-Policy` header config (server/edge)\n  * `<meta http-equiv=\"Content-Security-Policy\" ...>`\n  * CSP containing `unsafe-inline` or `unsafe-eval`\n  * `require-trusted-types-for` / `trusted-types` directives ([MDN Web Docs][1])\n\n* Third-party scripts:\n\n  * `<script src=\"https://...\">` without `integrity=`\n  * Tag manager snippets and dynamic script injection code paths ([MDN Web Docs][12])\n\n\n* DOM clobbering gadgets:\n\n  * `window.<name> || ...` and `document.<name> || ...` patterns\n  * security-sensitive usage of `window`/`document` properties as config sources ([OWASP Cheat Sheet Series][8])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted),\n* sink type (HTML parse, navigation, code execution, message handling, storage),\n* protective controls present (CSP, Trusted Types, sanitizers, strict allowlists, schema validation).\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary standards / platform docs:\n\n* W3C Content Security Policy Level 2 (HTML `<meta>` delivery restrictions; unsupported directives in meta CSP): `https://www.w3.org/TR/CSP2/` ([W3C][3])\n* MDN: CSP Guide (strict CSP, nonces/hashes, `unsafe-inline`/`unsafe-eval`, eval blocking): `https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP` ([MDN Web Docs][10])\n* MDN: `<meta http-equiv>` (CSP via meta and warning about meta-based security headers): `https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/meta/http-equiv` ([MDN Web Docs][1])\n* MDN: `frame-ancestors` (and note it’s not supported in `<meta>`): `https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/frame-ancestors` ([MDN Web Docs][18])\n\nDOM XSS and dangerous sinks:\n\n* OWASP: DOM Based XSS Prevention Cheat Sheet (dangerous sinks + safe patterns like `textContent`): `https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][2])\n* MDN: `innerHTML` (security considerations): `https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML` ([MDN Web Docs][19])\n* MDN: `insertAdjacentHTML` (security considerations): `https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML` ([MDN Web Docs][20])\n* MDN: `document.write()` / `document.writeln()` (security considerations): `https://developer.mozilla.org/en-US/docs/Web/API/Document/write` and `https://developer.mozilla.org/en-US/docs/Web/API/Document/writeln` ([MDN Web Docs][13])\n\nURL scheme hazards:\n\n* MDN: `javascript:` URLs (execution on navigation; discouraged; references `window.location`): `https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Schemes/javascript` ([MDN Web Docs][4])\n\nTrusted Types:\n\n* W3C: Trusted Types spec (DOM XSS sinks include `Element.innerHTML` and `Location.href` setters; goals and limitations): `https://www.w3.org/TR/trusted-types/` ([W3C][15])\n* MDN: `require-trusted-types-for` directive: `https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/require-trusted-types-for` ([MDN Web Docs][11])\n* MDN: `trusted-types` directive: `https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/trusted-types` ([MDN Web Docs][16])\n\nCross-window messaging:\n\n* MDN: `window.postMessage` (security guidance: specify targetOrigin; validate origin): `https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage` ([MDN Web Docs][5])\n* OWASP: HTML5 Security Cheat Sheet (Web Messaging guidance: explicit origin, strict checks, no `innerHTML`): `https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][6])\n\nThird-party scripts and integrity:\n\n* OWASP: Third Party JavaScript Management Cheat Sheet (risks and mitigations including SRI/mirroring): `https://cheatsheetseries.owasp.org/cheatsheets/Third_Party_Javascript_Management_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][7])\n* MDN: Subresource Integrity overview: `https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity` ([MDN Web Docs][12])\n* W3C: Subresource Integrity spec: `https://www.w3.org/TR/sri-2/` ([W3C][21])\n\nDOM clobbering:\n\n* OWASP: DOM Clobbering Prevention Cheat Sheet (named property access risk; example attacks involving `location.assign` and `javascript:`): `https://cheatsheetseries.owasp.org/cheatsheets/DOM_Clobbering_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][8])\n\n[1]: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/meta/http-equiv \"https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/meta/http-equiv\"\n[2]: https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html\"\n[3]: https://www.w3.org/TR/CSP2/ \"Content Security Policy Level 2\"\n[4]: https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Schemes/javascript \"javascript: URLs - URIs | MDN\"\n[5]: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage \"https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage\"\n[6]: https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html\"\n[7]: https://cheatsheetseries.owasp.org/cheatsheets/Third_Party_Javascript_Management_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Third_Party_Javascript_Management_Cheat_Sheet.html\"\n[8]: https://cheatsheetseries.owasp.org/cheatsheets/DOM_Clobbering_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/DOM_Clobbering_Prevention_Cheat_Sheet.html\"\n[9]: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/noopener \"https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/noopener\"\n[10]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP \"https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP\"\n[11]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/require-trusted-types-for \"https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/require-trusted-types-for\"\n[12]: https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity \"https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity\"\n[13]: https://developer.mozilla.org/en-US/docs/Web/API/Document/write \"https://developer.mozilla.org/en-US/docs/Web/API/Document/write\"\n[14]: https://developer.mozilla.org/en-US/docs/Web/API/Document/writeln \"https://developer.mozilla.org/en-US/docs/Web/API/Document/writeln\"\n[15]: https://www.w3.org/TR/trusted-types/ \"https://www.w3.org/TR/trusted-types/\"\n[16]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/trusted-types \"https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/trusted-types\"\n[18]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/frame-ancestors \"https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/frame-ancestors\"\n[19]: https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML \"https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML\"\n[20]: https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML \"https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML\"\n[21]: https://www.w3.org/TR/sri-2/ \"https://www.w3.org/TR/sri-2/\"\n","core/skills/builtin/security-best-practices/references/javascript-jquery-web-frontend-security.md":"# jQuery Frontend Security Spec (jQuery 4.0.x, modern browsers)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new jQuery-based frontend code.\n2. **Security review / vulnerability hunting** in existing jQuery-based code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session tokens, refresh tokens, CSRF tokens, session cookies).\n* MUST treat the browser as an attacker-controlled environment:\n\n  * Frontend checks (UI gating, “disable button”, hidden fields, client-side validation) MUST NOT be treated as authorization or a security boundary.\n  * Server-side authorization and validation MUST exist even if frontend is “correct”.\n* MUST NOT “fix” security by disabling protections (e.g., relaxing CSP to allow `unsafe-inline`, enabling JSONP “because it works”, adding broad CORS, disabling sanitization, suppressing security checks).\n* MUST provide evidence-based findings during audits: cite file paths, code snippets, and relevant configuration values.\n* MUST treat uncertainty honestly: if a protection might exist at the edge (CDN/WAF/reverse proxy headers like CSP), report it as “not visible in repo; verify at runtime/config”.\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new jQuery code or modify existing jQuery code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default patterns: text insertion, DOM node construction, allowlists, and proven sanitization libraries over custom escaping.\n* MUST avoid introducing new risky sinks (HTML string building, dynamic script loading, JSONP, inline script/event-handler attributes, unsafe URL assignment, unsafe object merging).\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a repo that uses jQuery (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in the structured format (see §2.3).\n\nRecommended audit order:\n\n1. jQuery sourcing, versions, and dependency hygiene (script tags, lockfiles, CDN usage, SRI).\n2. CSP / Trusted Types / security headers posture (in repo and at runtime if observable).\n3. DOM XSS: untrusted sources → jQuery sinks (`.html`, `.append`, `$(\"<…>\")`, `.load`, etc.).\n4. Script execution sinks: JSONP, `dataType:\"script\"`, `$.getScript`, dynamic `<script>` insertion.\n5. URL/attribute assignment (`href`, `src`, `style`, `on*` attributes).\n6. Prototype pollution / unsafe object merging (`$.extend` patterns).\n7. AJAX auth patterns + CSRF for cookie-based sessions.\n8. Third-party plugins and untrusted content rendering paths (comments, WYSIWYG, markdown-to-HTML).\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nExamples include:\n\n* Any data from the server that originates from users (user profiles, comments, “display name”, rich text, filenames).\n* Data from third-party APIs or services.\n* Browser-controlled sources:\n\n  * `location.href`, `location.search`, `location.hash`\n  * `document.URL`, `document.baseURI`, `document.referrer`\n  * `window.name`\n  * `localStorage` / `sessionStorage`\n  * `postMessage` event data (unless strict origin and schema validation exists)\n  * Any DOM content that could have been injected previously (stored XSS)\n\n### 2.2 High-risk “sinks” in jQuery contexts\n\nA sink is a code path where untrusted input can become interpreted as executable code or HTML.\n\nKey jQuery sink categories:\n\n* HTML insertion / parsing:\n\n  * DOM manipulation methods that accept HTML strings such as `.html()`, `.append()`, and related methods (see CVE notes below). ([NVD][1])\n  * `$(htmlString)` (when the argument can be interpreted as HTML markup).\n  * `jQuery.parseHTML(html, …, keepScripts)` especially with `keepScripts=true`. ([jQuery API][2])\n  * `.load(url)` (loads HTML into DOM; has special script execution behavior). ([jQuery API][3])\n* Script execution / dynamic code loading:\n\n  * `$.getScript()` / `$.ajax({ dataType: \"script\" })` (executes fetched JavaScript). ([jQuery API][4])\n  * JSONP (`dataType: \"jsonp\"` or implicit JSONP behavior) (executes remote JavaScript as a response). ([jQuery API][5])\n  * `eval`, `new Function`, `setTimeout(\"…\")`, `setInterval(\"…\")`, `$.globalEval` (if present)\n* Dangerous attribute assignment:\n\n  * Assigning untrusted strings to `href`, `src`, `srcdoc`, `style`, or event-handler attributes (`onload`, `onclick`, etc.)\n  * `javascript:` URLs are particularly dangerous and discouraged. ([MDN Web Docs][6])\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + function/component + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common jQuery-related security failures.\n\n### 3.1 Use a supported, patched jQuery version (MUST)\n\n* MUST use a supported jQuery major version and keep it updated.\n* As of 2026-01-27, the jQuery project ships jQuery 4.0.0 as the latest major release. ([blog.jquery.com][7])\n* If you must support very old browsers (notably IE < 11), jQuery 4 does not support them and you may need to stay on jQuery 3.x; treat this as a higher risk posture and patch aggressively. ([blog.jquery.com][7])\n\n### 3.2 Load jQuery safely (MUST)\n\n* MUST load jQuery only from:\n\n  * Your own build pipeline (bundled via npm/yarn + lockfile), or\n  * The official jQuery CDN / a trusted CDN with Subresource Integrity (SRI) enabled.\n* If loading from a CDN, SHOULD use SRI (`integrity`) and correct `crossorigin` settings; the jQuery project explicitly supports and recommends SRI on its CDN. (Retrieved from [jquery.com][8])\n\n### 3.3 CSP + Trusted Types (SHOULD, and MUST where available/required by policy)\n\n* SHOULD deploy a Content Security Policy (CSP) that reduces XSS impact (especially `script-src` restrictions and avoiding `unsafe-inline`). If not done through HTTP server, this can be done through the `<meta http-equiv=\"Content-Security-Policy\" content=\"...\">` tag. ([OWASP Cheat Sheet Series][9]) NOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n* SHOULD consider Trusted Types as a strong defense-in-depth against DOM XSS. ([W3C][10])\n* If you deploy the CSP directive `require-trusted-types-for`, then code MUST route DOM-injection through Trusted Types policies. ([MDN Web Docs][11])\n* Note: jQuery 4.0 explicitly added Trusted Types support so that TrustedHTML can be used with jQuery manipulation methods without violating `require-trusted-types-for`. ([blog.jquery.com][7])\n\n### 3.4 Security headers and cookie posture (defense in depth; SHOULD)\n\nEven though these are typically set server-side, they materially reduce the blast radius of jQuery-related mistakes. However if the context is only the frontend web application, these cannot be acted on.\n\n* SHOULD set common security headers (CSP, `X-Content-Type-Options: nosniff`, clickjacking protection via `frame-ancestors` / `X-Frame-Options`, `Referrer-Policy`). ([OWASP Cheat Sheet Series][12])\n* SHOULD avoid storing long-lived secrets/tokens in places accessible to JavaScript (like `localStorage`) unless the threat model explicitly accepts “XSS == account takeover”. This is not jQuery-specific, but jQuery-heavy DOM manipulation increases the chance of DOM XSS regressions; reduce the payoff.\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### JQ-SUPPLY-001: jQuery MUST be patched; do not run known vulnerable versions\n\nSeverity: Medium (High if internet-facing app AND version is known-vulnerable)\n\nNOTE: Before performing an upgrade, get concent from the user and try to understand if they have reasons to keep it back. Upgrading can break applications in unexpected ways. Report and recommend upgrades rather than just performing them.\n\nRequired:\n\n* MUST NOT use jQuery versions with known high-impact vulnerabilities when a patched version exists.\n* MUST upgrade past:\n\n  * CVE-2019-11358 (prototype pollution in jQuery before 3.4.0). ([NVD][13])\n  * CVE-2020-11022 / CVE-2020-11023 (XSS risks in DOM manipulation methods when handling untrusted HTML; patched in 3.5.0). ([NVD][1])\n\nInsecure patterns:\n\n* Script tags or package manifests referencing old jQuery (e.g., `jquery-1.*`, `jquery-2.*`, `jquery-3.3.*`, `jquery-3.4.*`, `jquery-3.4.1`, etc.).\n* Bundled vendor directories containing old minified jQuery without an upgrade path.\n\nDetection hints:\n\n* Search HTML/templates for `jquery-` and parse version strings.\n* Check `package.json`, `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`.\n* Check `vendor/`, `public/`, `static/`, `assets/`, `wwwroot/` for `jquery*.js`.\n\nFix:\n\n* Upgrade to current jQuery (prefer latest stable major; as of 2026-01-27, 4.0.0 is current). ([blog.jquery.com][7])\n* If upgrade is constrained, at minimum upgrade beyond the CVE thresholds and add compensating controls (strong CSP, strict sanitization, remove risky APIs like JSONP, remove deep-extend of untrusted objects).\n\nNotes:\n\n* If a product requirement forces old versions, report as “accepted risk requiring compensating controls”.\n\n---\n\n### JQ-SUPPLY-002: Third-party script loading SHOULD use integrity and trusted origins\n\nSeverity: High\n\nRequired:\n\n* MUST load jQuery and plugins only from trusted origins.\n* If loaded from CDN, SHOULD use SRI (`integrity`) and correct `crossorigin` handling. ([jquery.com][8])\n\nInsecure patterns:\n\n* `<script src=\"https://…/jquery.min.js\"></script>` with no `integrity`.\n* Loading jQuery from random third-party CDNs without an explicit trust decision.\n\nDetection hints:\n\n* Scan HTML for `<script src=` and check for `integrity=` + `crossorigin=`.\n* Identify dynamic script insertion with untrusted URLs (see JQ-EXEC-001).\n\nFix:\n\n* Prefer bundling via npm + lockfile.\n* If using CDN, copy official script tag (jQuery CDN supports SRI). ([jquery.com][8])\n\nNote: If unable to get the correct SRI tag, skip this step but tell the user. If you end up using the wrong one the app will not function. In that case remove it and inform the user.\n\n---\n\n### JQ-XSS-001: Untrusted data MUST NOT be inserted as HTML via jQuery DOM-manipulation methods\n\nSeverity: High (if attacker-controlled content reaches these sinks)\n\nRequired:\n\n* MUST treat any HTML string insertion as a code execution boundary.\n* MUST use safe alternatives for untrusted text:\n\n  * `.text(untrusted)` (text, not HTML). ([jQuery API][14])\n  * `.val(untrusted)` for form fields. ([jQuery API][15])\n  * Create elements and set text/attributes safely instead of concatenating HTML strings.\n\nInsecure patterns (examples):\n\n* `$(selector).html(untrusted)`\n* `$(selector).append(untrusted)`\n* `$(selector).before(untrusted)` / `.after(untrusted)` / `.replaceWith(untrusted)` / `.wrap(untrusted)` (and similar)\n* Building markup: `\"<div>\" + untrusted + \"</div>\"` then passing to jQuery\n\nDetection hints:\n\n* Grep for: `.html(`, `.append(`, `.prepend(`, `.before(`, `.after(`, `.replaceWith(`, `.wrap(`, `.wrapAll(`, `.wrapInner(`\n* Trace dataflow into these calls from sources in §2.1.\n\nFix:\n\n* Replace with `.text()` / `.val()` or node construction:\n\n  * `const $el = $(\"<span>\").text(untrusted); container.append($el);`\n* If the output must contain limited markup, see JQ-XSS-002 (sanitization).\n\nNotes:\n\n* Older jQuery versions had additional edge cases even when attempting sanitization; patched in 3.5.0+. Still: never rely on “string sanitization” alone—prefer structured creation or proven sanitizers. ([GitHub][16])\n\n---\n\n### JQ-XSS-002: If rendering user-controlled HTML is required, it MUST be sanitized with a proven HTML sanitizer\n\nSeverity: Medium (High if rich HTML is attacker-controlled and sanitizer is weak/misconfigured)\n\nRequired:\n\n* MUST NOT “roll your own” HTML sanitizer with regexes.\n* If user-controlled HTML must be displayed (e.g., rich text comments), MUST sanitize using a well-maintained HTML sanitizer and a restrictive allowlist.\n\n  * DOMPurify is a common choice; use conservative configuration and keep it updated. ([GitHub][17])\n  * Where available, MAY consider the browser HTML Sanitizer API (note: limited browser availability). ([MDN Web Docs][18])\n* SHOULD pair sanitization with CSP and, where feasible, Trusted Types for defense in depth. ([OWASP Cheat Sheet Series][9])\n\nInsecure patterns:\n\n* Regex-based “strip `<script>`” or “escape `<`” attempts followed by `.html()` insertion.\n* DOMPurify (or similar) configured to allow overly broad tags/attributes, or configuration that’s not reviewed.\n\nDetection hints:\n\n* Search for “sanitize” helper functions, regex replacing `<`/`>` patterns, or “allow all tags” configs.\n* Identify features that render user-generated “rich text” or “custom HTML”.\n* Check if sanitizer results are inserted with `.html()` or equivalent sinks.\n\nFix:\n\n* Introduce a sanitizer with strict allowlist.\n* Centralize the “sanitize then inject” pattern into a single reviewed module.\n* Add regression tests covering representative malicious inputs (don’t store payloads in logs or telemetry).\n\nFalse positive notes:\n\n* If content is guaranteed trusted (e.g., compiled templates shipped by you), document the trust boundary and why it is not attacker-controlled.\n\n---\n\n### JQ-XSS-003: `$(untrustedString)` and `jQuery.parseHTML` MUST NOT process attacker-controlled markup\n\nSeverity: High (if attacker-controlled)\n\nRequired:\n\n* MUST NOT pass attacker-controlled strings to `$()` when they might be interpreted as HTML.\n* MUST treat `jQuery.parseHTML(html, …, keepScripts)` as a high-risk primitive; keepScripts MUST be `false` for any untrusted input. ([jQuery API][2])\n\nInsecure patterns:\n\n* `const $node = $(untrusted);`\n* `$.parseHTML(untrusted, /* context */, true)` (scripts preserved)\n\nDetection hints:\n\n* Search for `$(` calls where the argument is not a static selector or static markup.\n* Search for `$.parseHTML(` and inspect the `keepScripts` argument.\n\nFix:\n\n* Use DOM creation with constant tag names and `.text()` for untrusted values.\n* If parsing HTML is necessary, sanitize first (JQ-XSS-002) and keep scripts disabled.\n\n---\n\n### JQ-XSS-004: `.load()` MUST be treated as an HTML+script injection surface\n\nSeverity: Medium (High if URL/content is attacker-controlled)\n\nRequired:\n\n* MUST NOT use `.load()` with attacker-controlled URLs or attacker-controlled HTML fragments.\n* MUST understand jQuery `.load()` script behavior:\n\n  * Without a selector in the URL, content is passed to `.html()` before scripts are removed, which can execute scripts. ([jQuery API][3])\n* SHOULD prefer `fetch()`/XHR to retrieve data, then render with safe DOM creation or sanitize explicitly.\n\nInsecure patterns:\n\n* `$(\"#target\").load(untrustedUrl)`\n* `$(\"#target\").load(\"/path?param=\" + untrusted)`\n\nDetection hints:\n\n* Search for `.load(` across JS/TS files.\n* Identify whether a selector is appended to the URL (the behavior differs). ([jQuery API][3])\n* Trace whether the URL can be influenced by user input.\n\nFix:\n\n* Replace `.load()` with:\n\n  * `fetch()` to retrieve JSON, then render via `.text()` / node construction, or\n  * `fetch()` to retrieve HTML, sanitize it, then inject.\n* If `.load()` must remain, ensure the URL is constant or strictly allowlisted and the returned content is trusted.\n\n---\n\n### JQ-EXEC-001: Dynamic script execution and script fetching MUST NOT be reachable from untrusted input\n\nSeverity: High\n\nRequired:\n\n* MUST NOT fetch-and-execute scripts from untrusted or user-influenced URLs.\n* MUST treat these as code execution primitives:\n\n  * `$.getScript(url)` executes the fetched script in the global context. ([jQuery API][4])\n  * `$.ajax({ dataType: \"script\" })` and other script-typed requests that execute responses.\n* SHOULD remove these patterns unless there is a strong, reviewed justification.\n\nInsecure patterns:\n\n* `$.getScript(untrustedUrl)`\n* `$.ajax({ url: untrustedUrl, dataType: \"script\" })`\n* Dynamic `<script src=...>` injection where `src` is derived from untrusted input.\n\nDetection hints:\n\n* Search for `getScript(`, `dataType: \"script\"`, `globalEval`, `eval`, `new Function`.\n* Look for “plugin loader” or “theme loader” features that accept URLs.\n\nFix:\n\n* Bundle scripts at build time.\n* If runtime-loading is required, restrict to allowlisted, versioned, integrity-checked assets (and ideally still avoid runtime code loading).\n\n---\n\n### JQ-AJAX-001: JSONP MUST be disabled unless the endpoint is fully trusted (and even then, avoid)\n\nSeverity: Medium (High if attacker can influence URL/endpoint)\n\nRequired:\n\n* MUST NOT use JSONP for untrusted endpoints because it executes JavaScript responses.\n* When using `$.ajax`, MUST explicitly disable JSONP for non-fully-trusted targets; jQuery’s own docs recommend setting `jsonp: false` “for security reasons” if you don’t trust the target. ([jQuery API][5])\n* SHOULD prefer CORS with JSON (`dataType: \"json\"`) and explicit origin allowlists server-side.\n\nInsecure patterns:\n\n* `dataType: \"jsonp\"`\n* URLs containing `callback=?` or patterns that trigger JSONP behavior. callback arguments are historically XSS vectors.\n* `$.get(untrustedUrl)` without pinning `dataType` and disabling JSONP (risk depends on options and jQuery behavior)\n\nDetection hints:\n\n* Search for `jsonp`, `dataType: \"jsonp\"`, `callback=?`.\n* Search for cross-domain AJAX where the URL is not hard-coded or allowlisted.\n\nFix:\n\n* Use JSON over HTTPS with CORS configured server-side.\n* Set:\n\n  * `dataType: \"json\"`\n  * `jsonp: false` (defense in depth when URL might be ambiguous) ([jQuery API][5])\n\n---\n\n### JQ-AJAX-002: State-changing AJAX requests using cookie auth MUST be CSRF-protected\n\nSeverity: High\n\nNOTE: This only matters when using cookie based auth. If the request use Authorization header, there is no CSRF potential.\n\nRequired:\n\n* If authentication uses cookies, MUST protect state-changing requests (POST/PUT/PATCH/DELETE) against CSRF.\n* SHOULD use server-verified CSRF tokens; for AJAX calls, tokens are commonly sent in a custom header. ([OWASP Cheat Sheet Series][19])\n* MUST NOT treat “it’s an AJAX request” as CSRF protection by itself.\n\nInsecure patterns:\n\n* `$.post(\"/transfer\", {...})` or `$.ajax({ method: \"POST\", ... })` with cookie auth and no CSRF token/header.\n* “CSRF protection” that only checks for `X-Requested-With` (defense-in-depth only, not primary).\n\nDetection hints:\n\n* Enumerate state-changing AJAX calls and locate whether they include CSRF tokens.\n* Identify how the server expects CSRF validation (meta tag, cookie-to-header double submit, synchronizer token, etc.).\n\nFix:\n\n* Add CSRF token inclusion in a centralized place, e.g., `$.ajaxSetup({ headers: { \"X-CSRF-Token\": token } })`, and ensure server verifies.\n* Follow OWASP CSRF guidance for token properties and validation. ([OWASP Cheat Sheet Series][19])\n\nFalse positive notes:\n\n* If auth is not cookie-based (e.g., Authorization header bearer token) CSRF risk is different; verify actual auth mechanism.\n\n---\n\n### JQ-ATTR-001: Untrusted values MUST NOT be written into dangerous attributes without validation/allowlisting\n\nSeverity: Low (High for events like onclick)\n\nRequired:\n\n* MUST validate/allowlist URLs written into `href`, `src`, `action`, etc.\n* MUST block dangerous schemes; `javascript:` URLs are discouraged because they can execute code. ([MDN Web Docs][6])\n* MUST NOT set event-handler attributes (`onclick`, `onerror`, etc.) from strings.\n* SHOULD avoid writing untrusted strings into `style` attributes; prefer toggling predefined CSS classes.\n\nInsecure patterns:\n\n* `$(\"a\").attr(\"href\", untrustedUrl)`\n* `$(\"img\").attr(\"src\", untrustedUrl)`\n* `$(el).attr(\"style\", untrustedCss)`\n* `$(el).attr(\"onclick\", untrustedJs)`\n\nDetection hints:\n\n* Search for `.attr(\"href\"`, `.attr(\"src\"`, `.attr(\"style\"`, `.prop(\"href\"`, `.prop(\"src\"`.\n* Trace whether inputs come from URL params, server JSON, DOM, or storage.\n\nFix:\n\n* Parse and validate URLs with `new URL(value, location.origin)` and allowlist protocols (`https:` etc.) and hostnames when needed.\n* For navigation targets, prefer relative paths you construct rather than full URLs.\n* Replace `style` strings with `addClass/removeClass` using predefined class names.\n\n---\n\n### JQ-SELECTOR-001: User-controlled selector fragments MUST be escaped with `jQuery.escapeSelector`\n\nSeverity: Medium (can become High if it enables wrong-element selection in security-relevant UI)\n\nRequired:\n\n* If you must select by an ID/class that can contain special CSS characters, SHOULD use `jQuery.escapeSelector()` (available in jQuery 3.0+). ([jQuery API][20])\n* MUST NOT concatenate raw attacker-controlled strings into selector expressions.\n\nInsecure patterns:\n\n* `$(\"#\" + untrustedId)`\n* `$(\"[data-id='\" + untrusted + \"']\")` (especially without strict quoting/escaping)\n\nDetection hints:\n\n* Search for `\"#\" +`, `\". \" +`, or template strings used inside `$(` selectors.\n* Look for “select by user-supplied id”.\n\nFix:\n\n* `$(\"#\" + $.escapeSelector(untrustedId))` ([jQuery API][20])\n* Prefer stable internal IDs over user-derived selectors.\n\nNotes:\n\n* This is often “robustness”, but it can become security-relevant if incorrect selection causes UI to reveal/modify the wrong data or skip security-related prompts.\n\n---\n\n### JQ-PROTOTYPE-001: Do not deep-merge untrusted objects; prevent prototype pollution\n\nSeverity: Medium\n\nRequired:\n\n* MUST NOT deep-merge (`$.extend(true, …)`) attacker-controlled objects into application objects without filtering dangerous keys.\n* MUST ensure jQuery is >= 3.4.0 to avoid CVE-2019-11358 prototype pollution behavior. ([NVD][13])\n\nInsecure patterns:\n\n* `$.extend(true, target, untrustedObj)`\n* `$.extend(true, {}, defaults, untrustedObj)` where untrustedObj comes from URL/JSON/storage\n\nDetection hints:\n\n* Search for `$.extend(true` and inspect sources of merged objects.\n* Search for “merge options” / “apply config” patterns using untrusted JSON.\n\nFix:\n\n* Prefer:\n\n  * Shallow merges with an allowlisted set of keys, or\n  * A safe merge helper that explicitly rejects `__proto__`, `prototype`, `constructor`, and nested occurrences.\n* Keep jQuery patched.\n\n---\n\n### JQ-CSP-001: CSP and Trusted Types SHOULD be used to make DOM XSS harder to introduce and exploit\n\nSeverity: Medium\n\nRequired:\n\n* SHOULD deploy CSP as defense-in-depth against XSS. ([OWASP Cheat Sheet Series][9])\n* If enabling Trusted Types (`require-trusted-types-for`), MUST ensure DOM injection goes through Trusted Types policies. ([MDN Web Docs][11])\n* When using jQuery 4, SHOULD take advantage of its Trusted Types support (TrustedHTML inputs). ([blog.jquery.com][7])\n\nInsecure patterns:\n\n* “Fixing” a jQuery feature by weakening CSP (`script-src 'unsafe-inline'` / `'unsafe-eval'`) without a compensating plan.\n* No CSP on applications that render user content or manipulate DOM heavily.\n\nDetection hints:\n\n* Look for CSP headers (server configs, framework middleware, meta tags).\n* If not visible in repo, flag as “verify at edge/runtime”.\n\nFix:\n\n* Add CSP incrementally; start by eliminating inline scripts and inline event handlers, then tighten `script-src`.\n* Add Trusted Types where supported and feasible.\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* jQuery version / sourcing:\n\n  * `jquery-*.js` in `vendor/` or `static/`\n  * `package.json` dependency `jquery` pinned to old versions\n  * CDN script tags lacking `integrity`/`crossorigin` ([jquery.com][8])\n* HTML injection sinks (DOM XSS):\n\n  * `.html(`, `.append(`, `.prepend(`, `.before(`, `.after(`, `.replaceWith(`, `.wrap(`\n  * `$(` where argument might be HTML / template strings\n  * `$.parseHTML(` especially with `keepScripts=true` ([jQuery API][2])\n  * `.load(` (and whether selector is appended; script behavior differs) ([jQuery API][3])\n* Script execution / dynamic code:\n\n  * `$.getScript(`, `dataType: \"script\"` ([jQuery API][4])\n  * `dataType: \"jsonp\"` or `jsonp:` usage; `callback=?` patterns ([jQuery API][5])\n  * `eval`, `new Function`, `setTimeout(\"…\")`, `$.globalEval`\n* Dangerous attribute writes:\n\n  * `.attr(\"href\", …)`, `.attr(\"src\", …)`, `.attr(\"style\", …)`\n  * Any assignment of `javascript:`-like schemes or suspicious URL construction ([MDN Web Docs][6])\n* Selector construction:\n\n  * `$(\"#\" + user)` and similar; fix via `$.escapeSelector` ([jQuery API][20])\n* Prototype pollution:\n\n  * `$.extend(true, …, userObj)`; ensure jQuery >= 3.4.0 and filter dangerous keys ([NVD][13])\n* CSRF posture for AJAX:\n\n  * `$.post(` / `$.ajax({ method: ... })` with cookies and no CSRF token/header ([OWASP Cheat Sheet Series][19])\n* Defense-in-depth:\n\n  * Absence of CSP/security headers in configs (or not visible; require runtime verification) ([OWASP Cheat Sheet Series][12])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (HTML insertion / script execution / attribute / selector / object merge)\n* protective controls present (sanitizer, allowlists, CSP, Trusted Types, CSRF validation)\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary jQuery project documentation and release notes:\n\n* jQuery 4.0.0 release notes (Trusted Types/CSP changes; version info): `https://blog.jquery.com/2026/01/17/jquery-4-0-0/`. ([blog.jquery.com][7])\n* Download jQuery (latest version info; CDN + SRI guidance): `https://jquery.com/download/`. ([jquery.com][8])\n* jQuery API: `.html()`: `https://api.jquery.com/html/`. ([jQuery API][21])\n* jQuery API: `.text()`: `https://api.jquery.com/text/`. ([jQuery API][14])\n* jQuery API: `.append()`: `https://api.jquery.com/append/`. ([jQuery API][22])\n* jQuery API: `.load()` (script execution behavior): `https://api.jquery.com/load/`. ([jQuery API][3])\n* jQuery API: `jQuery.parseHTML(…, keepScripts)`: `https://api.jquery.com/jQuery.parseHTML/`. ([jQuery API][2])\n* jQuery API: `$.ajax()` (`jsonp: false` security note): `https://api.jquery.com/jQuery.ajax/`. ([jQuery API][5])\n* jQuery API: `$.getScript()` (executes script): `https://api.jquery.com/jQuery.getScript/`. ([jQuery API][4])\n* jQuery API: `jQuery.escapeSelector()`: `https://api.jquery.com/jQuery.escapeSelector/`. ([jQuery API][20])\n\njQuery vulnerabilities / advisories:\n\n* NVD CVE-2019-11358 (prototype pollution; jQuery < 3.4.0): `https://nvd.nist.gov/vuln/detail/CVE-2019-11358`. ([NVD][13])\n* NVD CVE-2020-11022 (XSS risk in DOM manipulation methods; patched in 3.5.0): `https://nvd.nist.gov/vuln/detail/CVE-2020-11022`. ([NVD][1])\n* NVD CVE-2020-11023 (XSS risk involving `<option>`; patched in 3.5.0): `https://nvd.nist.gov/vuln/detail/CVE-2020-11023`. ([NVD][23])\n* GitHub Security Advisory GHSA-gxr4-xjj5-5px2 (jQuery htmlPrefilter XSS; patched in 3.5.0): `https://github.com/jquery/jquery/security/advisories/GHSA-gxr4-xjj5-5px2`. ([GitHub][16])\n\nOWASP Cheat Sheet Series (web app security foundations relevant to jQuery usage):\n\n* XSS Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html`. ([OWASP Cheat Sheet Series][24])\n* DOM-based XSS Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html`. ([OWASP Cheat Sheet Series][25])\n* CSRF Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html`. ([OWASP Cheat Sheet Series][19])\n* HTTP Security Headers: `https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html`. ([OWASP Cheat Sheet Series][12])\n* Content Security Policy Cheat Sheet: `https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html`. ([OWASP Cheat Sheet Series][9])\n\nBrowser/platform references (SRI, CSP, Trusted Types, and dangerous URL schemes):\n\n* MDN: Subresource Integrity (SRI): `https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity`. ([MDN Web Docs][26])\n* W3C: SRI specification: `https://www.w3.org/TR/sri-2/`. ([W3C][27])\n* MDN: CSP guide: `https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP`. ([MDN Web Docs][28])\n* MDN: `require-trusted-types-for` directive: `https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/require-trusted-types-for`. ([MDN Web Docs][11])\n* MDN: Trusted Types API: `https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API`. ([MDN Web Docs][29])\n* W3C: Trusted Types specification: `https://www.w3.org/TR/trusted-types/`. ([W3C][10])\n* MDN: `javascript:` URL scheme warning: `https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Schemes/javascript`. ([MDN Web Docs][6])\n* DOMPurify project documentation: `https://github.com/cure53/DOMPurify`. ([GitHub][17])\n\n[1]: https://nvd.nist.gov/vuln/detail/cve-2020-11022?utm_source=chatgpt.com \"CVE-2020-11022 Detail - NVD\"\n[2]: https://api.jquery.com/jQuery.parseHTML/?utm_source=chatgpt.com \"jQuery.parseHTML()\"\n[3]: https://api.jquery.com/load/?utm_source=chatgpt.com \".load() | jQuery API Documentation\"\n[4]: https://api.jquery.com/jQuery.getScript/?utm_source=chatgpt.com \"jQuery.getScript()\"\n[5]: https://api.jquery.com/jQuery.ajax/?utm_source=chatgpt.com \"jQuery.ajax()\"\n[6]: https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Schemes/javascript?utm_source=chatgpt.com \"javascript: URLs - URIs - MDN Web Docs\"\n[7]: https://blog.jquery.com/2026/01/17/jquery-4-0-0/ \"jQuery 4.0.0 | Official jQuery Blog\"\n[8]: https://jquery.com/download/ \"Download jQuery | jQuery\"\n[9]: https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html?utm_source=chatgpt.com \"Content Security Policy - OWASP Cheat Sheet Series\"\n[10]: https://www.w3.org/TR/trusted-types/?utm_source=chatgpt.com \"Trusted Types\"\n[11]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/require-trusted-types-for?utm_source=chatgpt.com \"Content-Security-Policy: require-trusted-types-for directive\"\n[12]: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html?utm_source=chatgpt.com \"HTTP Security Response Headers Cheat Sheet\"\n[13]: https://nvd.nist.gov/vuln/detail/cve-2019-11358?utm_source=chatgpt.com \"CVE-2019-11358 Detail - NVD\"\n[14]: https://api.jquery.com/text/?utm_source=chatgpt.com \".text() | jQuery API Documentation\"\n[15]: https://api.jquery.com/val/?utm_source=chatgpt.com \".val() | jQuery API Documentation\"\n[16]: https://github.com/jquery/jquery/security/advisories/GHSA-gxr4-xjj5-5px2 \"Potential XSS vulnerability in jQuery.htmlPrefilter and related methods · Advisory · jquery/jquery · GitHub\"\n[17]: https://github.com/cure53/DOMPurify?utm_source=chatgpt.com \"DOMPurify - a DOM-only, super-fast, uber-tolerant XSS ...\"\n[18]: https://developer.mozilla.org/en-US/docs/Web/API/HTML_Sanitizer_API?utm_source=chatgpt.com \"HTML Sanitizer API - MDN Web Docs\"\n[19]: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html?utm_source=chatgpt.com \"Cross-Site Request Forgery Prevention Cheat Sheet\"\n[20]: https://api.jquery.com/jQuery.escapeSelector/?utm_source=chatgpt.com \"jQuery.escapeSelector()\"\n[21]: https://api.jquery.com/html/?utm_source=chatgpt.com \".html() | jQuery API Documentation\"\n[22]: https://api.jquery.com/append/?utm_source=chatgpt.com \".append() | jQuery API Documentation\"\n[23]: https://nvd.nist.gov/vuln/detail/cve-2020-11023?utm_source=chatgpt.com \"CVE-2020-11023 Detail - NVD\"\n[24]: https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html?utm_source=chatgpt.com \"Cross Site Scripting Prevention - OWASP Cheat Sheet Series\"\n[25]: https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html?utm_source=chatgpt.com \"DOM based XSS Prevention Cheat Sheet\"\n[26]: https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity?utm_source=chatgpt.com \"Subresource Integrity - Security - MDN Web Docs\"\n[27]: https://www.w3.org/TR/sri-2/?utm_source=chatgpt.com \"Subresource Integrity\"\n[28]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP?utm_source=chatgpt.com \"Content Security Policy (CSP) - HTTP - MDN Web Docs\"\n[29]: https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API?utm_source=chatgpt.com \"Trusted Types API - MDN Web Docs\"\n","core/skills/builtin/security-best-practices/references/javascript-typescript-nextjs-web-server-security.md":"# Next.js (TypeScript/JavaScript) Web Security Spec (Next.js 16.1.x, Node.js 20.9+)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new Next.js backend code (Route Handlers, API Routes, Server Actions, Proxy/Middleware).\n2. **Security review / vulnerability hunting** in existing Next.js repos (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\nTarget scope: Next.js **16.1.x** (latest line shown in the App Router docs) ([Next.js][1]), running on Node.js **20.9+** (per Next.js system requirements). ([Next.js][2])\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session cookies, OAuth tokens, `process.env` dumps, database URLs with credentials).\n* MUST NOT “fix” security by disabling protections (e.g., disabling origin checks, relaxing CORS to `*`, skipping authz checks, turning off cookie security flags, turning off CSP because it’s “hard”).\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and configuration values that justify each claim.\n* MUST treat uncertainty honestly: if a protection might exist in infrastructure (reverse proxy, CDN, WAF, platform headers), report it as “not visible in app code; verify at runtime/config”.\n* MUST assume all request-facing server code is reachable by attackers unless there is a clearly enforced auth boundary (not just “the UI doesn’t link to it”).\n* MUST treat TypeScript types as **non-security boundaries**: types do not validate runtime input; runtime checks are required. ([Next.js][3])\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new Next.js code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default APIs and proven libraries over custom security code.\n* MUST avoid introducing new risky sinks (dynamic code execution, unsafe redirects, serving user files as HTML, SSRF URL fetchers, building SQL strings, etc.).\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a Next.js repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. Deployment entrypoints and environment (Dockerfiles, `package.json` scripts, hosting config).\n2. Next.js config (`next.config.*`), Proxy/Middleware, routing patterns.\n3. Authentication, sessions, cookies.\n4. CSRF protections and state-changing endpoints (Server Actions, Route Handlers, API Routes).\n5. XSS (React + CSP) and unsafe HTML rendering.\n6. Cache/data-leak hazards (static rendering + caching + “use cache”).\n7. File handling (uploads/downloads) and path traversal.\n8. Injection classes (SQL/ORM misuse, command execution, unsafe deserialization).\n9. Outbound requests (SSRF).\n10. Redirect handling (open redirects).\n11. CORS and security headers.\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nIn Next.js backends, untrusted input includes:\n\nApp Router:\n\n* Route Handler params and request data:\n\n  * `context.params` (dynamic segments), search params (`request.url`, `new URL(request.url).searchParams`)\n  * `request.headers`, `request.cookies`\n  * `await request.json()`, `await request.formData()`, `await request.text()`\n* Dynamic APIs used in Server Components/Server Functions:\n\n  * `headers()` and `cookies()` values ([Next.js][4])\n\nPages Router:\n\n* `req.query`, `req.cookies`, `req.body` in `pages/api/*` handlers ([Next.js][3])\n\nPlus:\n\n* Anything from external systems (webhooks, third-party APIs, message queues)\n* Any persisted user content (DB rows) that originated from users\n\n### 2.2 State-changing request\n\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook send), or initiate privileged actions.\n\nSpecial note for Next.js:\n\n* **Server Actions** are invoked via network requests and can mutate state; treat them as state-changing endpoints. ([Next.js][5])\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + function/route name + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common Next.js backend misconfigurations.\n\n### 3.1 Run Next.js in production mode (MUST)\n\n* MUST run `next build` + `next start` (or the managed platform equivalent), not `next dev`. Dev mode has different error/reporting behavior and is not designed for production exposure. ([Next.js][6])\n* MUST ensure `NODE_ENV=production` in production (Next.js defaults `NODE_ENV` based on command; verify the runtime environment). ([Next.js][7])\n\n### 3.2 Put a reverse proxy / edge layer in front when self-hosting (MUST for public internet)\n\n* If self-hosting, MUST place a reverse proxy (e.g., nginx) or equivalent edge layer in front of the Next.js server to handle malformed requests, slow attacks, payload size limits, rate limiting, and similar concerns. ([Next.js][8])\n\n### 3.3 Baseline header/cookie posture (SHOULD)\n\n* SHOULD set a baseline of security headers globally (CSP, `X-Content-Type-Options`, clickjacking defense via CSP `frame-ancestors` and/or `X-Frame-Options`, etc.). Next.js provides guidance for implementing CSP via Proxy/headers. ([Next.js][7])\n* MUST ensure auth/session cookies use secure attributes (`Secure`, `HttpOnly`, `SameSite`) as appropriate. ([Next.js][9])\nIMPORTANT NOTE: Only set `Secure` in production environment. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n\n### 3.4 Clear separation between server-only and client code (MUST)\n\n* MUST prevent secrets and privileged logic from being bundled into client code.\n* MUST treat `NEXT_PUBLIC_*` environment variables as public (browser-exposed and inlined at build time). ([Next.js][7])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### NEXT-DEPLOY-001: Do not run `next dev` in production; ensure production mode behavior\n\nSeverity: High (if production)\n\nNOTE: If they are deploying to a specific Next.js hosting provider, they do not need to worry about this.\n\nRequired:\n\n* MUST NOT deploy `next dev` or any development server mode to production.\n* MUST ensure production builds and production runtime are used for any public deployment. ([Next.js][6])\n\nInsecure patterns:\n\n* `next dev` in Docker `CMD`, Procfile, platform start command.\n* `NODE_ENV=development` in production environment config.\n* Debug/dev-only endpoints or flags exposed publicly.\n\nDetection hints:\n\n* Search `package.json` scripts and deployment manifests for `next dev`.\n* Search infra for `NODE_ENV=development` or missing `NODE_ENV`.\n* Check Kubernetes/PM2/systemd entrypoints for `next dev`.\n\nFix:\n\n* Use `next build` during CI/build and `next start` at runtime (or platform-native build/run).\n* Ensure environment sets `NODE_ENV=production`.\n\nNote:\n\n* Dev mode is fine for local development. Only flag if it is being used as a production entrypoint.\n\n---\n\n### NEXT-SUPPLY-001: Stay on supported Next.js releases; patch quickly for security advisories\n\nSeverity: High (Critical if known-vulnerable version)\n\nRequired:\n\n* MUST run a supported Next.js version line and apply security updates promptly. Next.js documents an LTS/support policy. ([Next.js][10])\n* MUST treat published advisories as urgent upgrade signals (e.g., update to a patched release). ([GitHub][11])\n\nInsecure patterns:\n\n* Running EOL Next.js major/minor without backported security fixes.\n* Ignoring advisories, or pinning `next` to a vulnerable range.\n\nDetection hints:\n\n* Check `package.json` and lockfiles for `next` version.\n* Compare against Next.js support policy and advisories.\n\nIMPORTANT: Any versions older than these minor versions are vulnerable to \"react2shell\" vulnerability (https://nextjs.org/blog/CVE-2025-66478):\n15.0.5\n15.1.9\n15.2.6\n15.3.6\n15.4.8\n15.5.7\n16.0.7\n\nFix:\n\n* Upgrade `next` to a supported and patched version.\n* Add a dependency update process + CI checks.\n\n\n---\n\n### NEXT-SECRETS-001: Secrets MUST NOT be committed or exposed to the browser\n\nSeverity: High (Critical if secret is client-exposed)\n\nRequired:\n\n* MUST store secrets in environment variables or a secret manager; MUST NOT commit `.env*` files.\n* MUST treat `.env*` as sensitive; Next.js warns you “almost never want to commit these files.” ([Next.js][7])\n* MUST treat any `NEXT_PUBLIC_*` environment variable as public and browser-visible (inlined into the client bundle at build time). ([Next.js][7])\n\nInsecure patterns:\n\n* `.env`, `.env.local`, `.env.production` committed to git.\n* `NEXT_PUBLIC_API_KEY`, `NEXT_PUBLIC_SECRET`, `NEXT_PUBLIC_DATABASE_URL`, etc.\n* Rendering `process.env` values into HTML or returning them from API routes.\n\nDetection hints:\n\n* Scan git history and repo files for `.env` content, `DB_PASS=`, `API_KEY=`, `SECRET=`.\n* Grep for `NEXT_PUBLIC_` and review any sensitive-looking names.\n* Search for `process.env` usage in Client Components (`\"use client\"`) and shared modules.\n\nFix:\n\n* Move secrets to server-only env vars (no `NEXT_PUBLIC_` prefix).\n* Ensure `.env*` is ignored and secrets are injected at deploy time.\n* Rotate leaked keys.\n\n---\n\n### NEXT-SECRETS-002: Avoid server-only → client bundling mistakes (server/client boundary is a security boundary)\n\nSeverity: High\n\nRequired:\n\n* MUST ensure server-only modules (DB clients, secret-dependent code) are not imported into Client Components or other client-bundled code paths.\n* SHOULD use server-only patterns/layers (e.g., a dedicated DAL and server-only modules) and treat boundary violations as security bugs. Next.js explicitly discusses the “server-only” concept for sensitive modules. ([Next.js][6])\n\nInsecure patterns:\n\n* Importing DB clients, admin SDKs, or secret-reading modules into `\"use client\"` components.\n* Shared `lib/` modules imported by both server and client code that reference secrets.\n\nDetection hints:\n\n* Search for `\"use client\"` and examine its imports for server-only dependencies.\n* Look for DB client packages (`pg`, `mysql2`, `mongoose`, `prisma`, admin SDKs) imported from `components/` or other client paths.\n* Search for `process.env` access in UI components.\n\nFix:\n\n* Refactor into `lib/server/*` and only import from server contexts (Route Handlers, Server Components, Server Actions).\n* Add an explicit “server-only” guard pattern (and/or tests) to prevent accidental imports.\n\n---\n\n### NEXT-AUTH-001: Authentication/authorization MUST be enforced server-side for every protected action\n\nSeverity: High\n\nRequired:\n\n* MUST enforce authn/authz in server-side code for:\n\n  * Route Handlers (`app/**/route.ts`) ([Next.js][1])\n  * API Routes (`pages/api/**`) ([Next.js][3])\n  * Server Actions (`\"use server\"` functions invoked by clients) ([Next.js][6])\n* MUST NOT rely on client-side checks (hiding UI, route guards on the client) as the only protection.\n\nInsecure patterns:\n\n* Sensitive Route Handlers with no session verification.\n* Server Actions that mutate data but do not validate user identity/permissions.\n* “Authorization” checks in React components only.\n\nDetection hints:\n\n* Enumerate all Route Handlers and API Routes; for each, identify whether it requires auth.\n* Grep for `\"use server\"` and review all exported actions for auth checks.\n* Search for admin actions triggered by query params / form submits.\n\nFix:\n\n* Centralize auth helpers and call them in every protected endpoint/action.\n* Implement least-privilege authorization checks (role/resource ownership) per action.\n\n---\n\n### NEXT-AUTH-002: Proxy/Middleware-based auth MUST NOT create route coverage gaps\n\nSeverity: High\n\nRequired:\n\n* If using **Proxy** or **Middleware** for authentication checks, MUST ensure it covers every route that needs protection.\n* Next.js documentation notes Proxy can use a `matcher`, and for auth it’s recommended Proxy runs on all routes. ([Next.js][12])\n* MUST treat `matcher` mistakes as an auth bypass risk.\n\nInsecure patterns:\n\n* Proxy/Middleware only matches “pages” but not `/api/*`, or only matches some route groups.\n* “Denylist” style matchers that miss alternative request forms (framework-internal variants, RSC navigations, etc.).\n\nDetection hints:\n\n* Inspect `proxy.ts` / `middleware.ts` and its `matcher`.\n* Compare matchers to the full set of routes (including `app/api/**` and `pages/api/**`).\n* Ensure static assets and Next internals are excluded only intentionally, and that sensitive routes are included.\n\nFix:\n\n* Prefer allowlisting protected route prefixes or running Proxy globally and doing internal allow/deny logic.\n* Add integration tests: request protected route without auth and assert denial.\n\nNotes:\n\n* Proxy is commonly used for “optimistic checks”; it is not a complete authorization system by itself. ([Next.js][12])\n\n---\n\n### NEXT-CSRF-001: Cookie-authenticated state-changing endpoints MUST be CSRF-protected\n\nSeverity: High\n\n- IMPORTANT NOTE: If cookies are not being used for auth (ie auth is via Authentication header or other passed token), then there is no CSRF risk.\n\nRequired:\n\n* MUST protect every state-changing endpoint that relies on cookies for auth (POST/PUT/PATCH/DELETE).\n* For **Server Actions**, Next.js performs an Origin/Host comparison to help prevent CSRF; do not disable or weaken it. ([Next.js][5])\n* If Server Actions must be callable from additional trusted origins (e.g., a trusted proxy domain), MUST use `allowedOrigins` with a strict allowlist. ([Next.js][5])\n* For **Route Handlers** and **API Routes**, MUST implement CSRF protections explicitly (tokens and/or strict Origin/Referer + SameSite + custom headers). Route Handlers are an “escape hatch” and require application-level security decisions. ([Next.js][6])\n\nInsecure patterns:\n\n* POST endpoints (including Server Actions) that mutate state and accept cross-site requests with no token/origin checks.\n* `allowedOrigins: ['*']` (or broad wildcards) or “reflect Origin” logic.\n* Using GET requests to change state.\n\nDetection hints:\n\n* Enumerate all state-changing endpoints and determine auth mechanism.\n* Search for `allowedOrigins` and confirm the list is small, specific, and justified. ([Next.js][5])\n* In Route Handlers/API Routes: look for missing CSRF token validation or missing Origin/Referer checks.\n\nFix:\n\n* Implement a CSRF token strategy for cookie-auth endpoints.\n* Keep cookies `SameSite=Lax` or `Strict` when compatible; don’t treat SameSite alone as sufficient.\n* Use strict Origin validation for JSON API endpoints, especially when not using CSRF tokens.\n\nNotes:\n\n* XSS can defeat CSRF protections; CSRF defenses do not replace XSS prevention.\n\n---\n\n### NEXT-SESS-001: Session cookies MUST use secure attributes in production\n\nSeverity: Medium\n\nRequired (production, HTTPS):\n\n* MUST set session/auth cookies with:\n\n  * `Secure: true` (HTTPS-only) IMPORTANT NOTE: Only set `Secure` in production environment. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n  * `HttpOnly: true` (not readable by JS)\n  * `SameSite: 'Lax'` (recommended) or `'Strict'` if compatible\n* Only use `SameSite: 'none'` when you truly need cross-site cookies, and then MUST also set `Secure`. Cookie options are supported in Next.js cookie APIs. ([Next.js][9])\n\nInsecure patterns:\n\n* `secure: false` in production.\n* `httpOnly: false` for auth cookies.\n* `sameSite: 'none'` without a clear need, especially on cookie-authenticated state-changing endpoints.\n\nDetection hints:\n\n* Search for cookie setting sites (`cookies().set(...)`, `Set-Cookie` headers, auth library cookie config).\n* Review cookie options used in Route Handlers and Server Actions. ([Next.js][9])\n\nFix:\n\n* Set secure cookie attributes at the auth/session layer.\n* Reduce cookie scope: avoid wide `domain` unless you explicitly need subdomain-wide cookies.\n\n---\n\n### NEXT-SESS-002: Sessions MUST be bounded and resistant to fixation/replay\n\nSeverity: Low\n\nRequired:\n\n* SHOULD set bounded session lifetimes appropriate to the app.\n* SHOULD rotate session identifiers on login and privilege changes.\n* MUST NOT store sensitive secrets directly in client-readable storage (including cookies that are not encrypted).\n\nInsecure patterns:\n\n* Long-lived admin sessions with no rotation.\n* “Remember me forever” for privileged roles without additional risk controls.\n* Storing access tokens/refresh tokens in non-HttpOnly cookies or localStorage.\n\nDetection hints:\n\n* Review auth library configuration for expiration and rotation.\n* Search for `localStorage.setItem('token'...)` and non-HttpOnly cookie usage.\n\nFix:\n\n* Use short lifetimes for privileged sessions; refresh with rotation.\n* Store only opaque session IDs in cookies; keep sensitive material server-side.\n\n---\n\n### NEXT-INPUT-001: Runtime input validation is mandatory (TypeScript is not validation)\n\nSeverity: High\n\nRequired:\n\n* MUST validate and normalize all attacker-controlled input at runtime (schemas, type checks, bounds).\n* Next.js API Routes explicitly note `req.body` is `any` and must be validated before use. ([Next.js][3])\n* MUST validate Server Action arguments (treat as hostile). ([Next.js][6])\n\nInsecure patterns:\n\n* Trusting `req.body` shape directly.\n* Passing `params.id`/`searchParams` directly into DB queries or file paths.\n* Parsing JSON and then assuming types without validation.\n\nDetection hints:\n\n* Identify endpoints that accept JSON/form input and check for schema validation.\n* Grep for `req.body.` usage and for `await request.json()` usage in Route Handlers; verify validation exists.\n\nFix:\n\n* Add schema validation (e.g., zod/yup/valibot) and reject invalid input with 4xx.\n* Validate IDs as strict types (UUID/int) and enforce length/charset constraints.\n\n---\n\n### NEXT-HEADERS-001: Essential security headers MUST be set (in app or at the edge)\n\nSeverity: Low\n\nRequired (typical web app):\n\n* SHOULD set:\n\n  * CSP (`Content-Security-Policy`) (see NEXT-CSP-001)\n  * `X-Content-Type-Options: nosniff`\n  * Clickjacking defense (`frame-ancestors` in CSP and/or `X-Frame-Options`)\n  * `Referrer-Policy` and `Permissions-Policy` when appropriate\n* MUST ensure cookies are set with secure attributes (see NEXT-SESS-001). ([Next.js][9])\n\nInsecure patterns:\n\n* No security headers anywhere (app or edge).\n* Allowing iframing unintentionally.\n* `Content-Type` sniffing possible due to missing `nosniff`.\n\nDetection hints:\n\n* Check `proxy.ts` / middleware for `response.headers.set(...)`. ([Next.js][7])\n* If not visible in app code, flag as “verify at edge/CDN”.\n\nFix:\n\n* Set headers centrally (Proxy/Middleware or other centralized mechanism).\n* Ensure consistent headers across routes.\n\n---\n\n### NEXT-CSP-001: Use a CSP to reduce XSS impact; prefer nonces for scripts\n\nSeverity: Medium\n\nNOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n\nRequired:\n\n* SHOULD deploy a CSP, ideally with nonces for scripts.\n* SHOULD follow Next.js guidance for CSP implementation (including nonce generation and header application). ([Next.js][7])\n* MUST avoid loosening CSP as a “fix” (e.g., `script-src 'unsafe-inline'`) without explicit risk acceptance.\n\nInsecure patterns:\n\n* CSP missing on apps that display user-generated HTML/markdown.\n* CSP that broadly enables inline scripts or eval without strict justification.\n\nDetection hints:\n\n* Search for `Content-Security-Policy` header setting and examine its directives.\n* Check use of `next/script` and whether a nonce is provided when CSP requires it.\n\nFix:\n\n* Implement CSP per Next.js guidance; use a nonce and apply it consistently.\n* Reduce inline scripts; avoid `eval`.\n\nNotes:\n\n* CSP is defense-in-depth; it does not replace proper output encoding and sanitization.\n\n---\n\n### NEXT-XSS-001: Prevent reflected/stored XSS in React/Next rendering\n\nSeverity: High\n\nRequired:\n\n* MUST rely on React’s default escaping; MUST NOT insert untrusted HTML into the DOM without sanitization.\n* MUST treat these as high-risk sinks:\n\n  * `dangerouslySetInnerHTML`\n  * rendering user-controlled strings into `<script>` tags or event handler attributes\n* MUST avoid serving uploaded HTML as active HTML (serve as attachment or sanitize/transform).\n\nInsecure patterns:\n\n* `<div dangerouslySetInnerHTML={{ __html: userContent }} />` with no sanitizer.\n* Markdown renderers configured to allow raw HTML with no sanitizer.\n* Returning user content with `Content-Type: text/html` from a Route Handler.\n\nDetection hints:\n\n* Search for `dangerouslySetInnerHTML`, `__html:`.\n* Search for template-like string concatenation that builds HTML.\n* Review any “render HTML” or “preview” features.\n\nFix:\n\n* Sanitize untrusted HTML with a well-maintained sanitizer; prefer strict allowlists.\n* Prefer rendering user content as text, not HTML.\n* Add CSP to reduce impact.\n\n---\n\n### NEXT-ACTION-001: Server Actions MUST be treated like public endpoints\n\nSeverity: High (Critical for privileged actions)\n\nRequired:\n\n* MUST apply the same controls as for Route Handlers:\n\n  * authn/authz\n  * input validation\n  * CSRF/origin protections\n  * rate limiting for sensitive actions\n* MUST NOT assume Server Actions are “not reachable” or “internal”.\n* MUST understand Server Action request protections:\n\n  * Next.js compares Origin with host to mitigate CSRF; extra origins must be explicitly allowlisted via `allowedOrigins`. ([Next.js][5])\n\nInsecure patterns:\n\n* `\"use server\"` functions that update DB state with no auth check.\n* Adding overly broad `allowedOrigins` to “make it work”.\n\nDetection hints:\n\n* Grep for `\"use server\"` and inventory all exported actions.\n* Identify any action doing privileged writes; confirm it checks identity and permission.\n\nFix:\n\n* Wrap actions with an authz helper (fail closed).\n* Keep `allowedOrigins` minimal and audited.\n\n---\n\n### NEXT-ACTION-002: Do not accidentally leak secrets through Server Action closure/binding patterns\n\nSeverity: Medium (High if important secrets are exposed)\n\nRequired:\n\n* MUST treat Server Action closed-over values as sensitive and design intentionally.\n* Next.js notes that closed-over values are encrypted/signed, but values passed through `.bind` are not encrypted; do not rely on `.bind` to protect secrets. ([Next.js][6])\n* If using a stable encryption key for Server Actions across deployments, MUST treat it as a secret and store securely (do not commit/log it). ([Next.js][6])\n\nInsecure patterns:\n\n* `myAction.bind(null, process.env.SECRET)` or binding sensitive tokens/IDs that should not be client-influenced.\n* Logging action arguments that include secrets.\n\nDetection hints:\n\n* Search for `.bind(` on Server Action functions.\n* Search for `process.env` usage near Server Actions.\n\nFix:\n\n* Avoid binding secrets into actions; fetch secrets server-side inside the action.\n* Keep action arguments minimal and validated.\n\n---\n\n### NEXT-CACHE-001: Prevent data leaks via static rendering and shared caching\n\nSeverity: High (Critical if cross-user data leak)\n\nRequired:\n\n* MUST ensure pages/endpoints that return user-specific or sensitive data are not statically generated or cached in a shared way.\n* Route Handlers are not cached by default, but GET handlers can opt into caching/static behavior; do not do this for per-user data. ([Next.js][1])\n* MUST treat `use cache` and similar caching mechanisms as potentially cross-user unless explicitly proven private; do not cache per-user DB results in shared caches. ([Next.js][1])\n* SHOULD set explicit `Cache-Control: no-store` / `private` for sensitive responses (auth/session/user data APIs).\n\nInsecure patterns:\n\n* `export const dynamic = 'force-static'` on a route that returns user-specific data. ([Next.js][1])\n* Using `use cache` around a function that queries user-specific data without a per-user cache key. ([Next.js][1])\n* Returning auth/session responses from GET endpoints with caching enabled.\n\nDetection hints:\n\n* Search for `dynamic = 'force-static'`, `revalidate`, `use cache`, `cacheLife`, `unstable_cache`.\n* Inspect all GET Route Handlers that are cached/static and confirm they only return public data.\n* Confirm that use of `cookies()`/`headers()` (dynamic APIs) is not accidentally removed in ways that make a route static. ([Next.js][1])\n\nFix:\n\n* Mark sensitive routes as dynamic and set `Cache-Control: no-store`.\n* Ensure caching keys include user identity if caching is truly needed (and store it in a user-private cache).\n\n---\n\n### NEXT-FILES-001: User uploads MUST be validated, stored safely, and served safely\n\nSeverity: Medium\n\nRequired:\n\n* MUST enforce upload size limits at the edge and in application logic.\n* MUST validate file type using allowlists and content checks (not only extension).\n* MUST store uploads outside the `public/` directory (anything under `public/` is served as static content by default).\n* MUST serve potentially active formats safely (`Content-Disposition: attachment`) unless explicitly intended.\n\nInsecure patterns:\n\n* Accepting arbitrary file types and serving them back inline.\n* Using user-supplied filename as the storage path.\n* Writing uploads into `public/uploads/` and serving them directly.\n\nDetection hints:\n\n* Search for `formData()` / multipart parsing, `fs.writeFile`, storage SDK usage.\n* Look for any write path under `public/`.\n* Look for “download” endpoints that set `Content-Type: text/html` or serve user files inline.\n\nFix:\n\n* Use a dedicated object store (S3/GCS) or a safe server-side directory outside static roots.\n* Generate random server-side filenames; store metadata separately.\n\n---\n\n### NEXT-PATH-001: Prevent path traversal and unsafe file access\n\nSeverity: High\n\nRequired:\n\n* MUST NOT use user-controlled strings as filesystem paths.\n* MUST validate and normalize identifiers; use allowlists and safe base directories.\n* MUST avoid reading arbitrary files based on request parameters.\n\nInsecure patterns:\n\n* `fs.readFile(request.nextUrl.searchParams.get('path'))`\n* `path.join(base, userPath)` without normalization + boundary checks\n\nDetection hints:\n\n* Search for `fs.` usage in Route Handlers/API Routes.\n* Search for `path.join`/`path.resolve` fed by request params.\n\nFix:\n\n* Use opaque IDs that map to server-side stored paths.\n* Enforce that resolved paths remain within an intended base directory.\n* Sanitize and disallow `..` from being used when creating urls\n\n---\n\n### NEXT-SSRF-001: Outbound requests using user-influenced URLs MUST be restricted\n\nSeverity: Medium (High in internal networks)\n\nNOTE: This is mostly only applicable to apps which will be deployed in a cloud/LAN setup or have other http services on the same box. Sometimes the feature requires this functionality unavoidably (webhooks).\n\nRequired:\n\n* MUST treat any server-side `fetch()` to a user-provided URL as high-risk.\n* SHOULD allowlist destinations (hosts/domains) for URL fetch features.\n* SHOULD block:\n\n  * localhost / private IP ranges / link-local\n  * cloud metadata endpoints\n* MUST restrict protocols to `http:` and `https:`.\n* SHOULD set strict timeouts and restrict redirects.\n\nInsecure patterns:\n\n* `await fetch(req.query.url)` or `await fetch((await request.json()).url)`\n* “URL preview” endpoints that fetch arbitrary URLs.\n\nDetection hints:\n\n* Search for `fetch(` in server code and trace where the URL comes from.\n* Look for “webhook tester”, “preview”, “import from URL” features.\n\nFix:\n\n* Parse URL, enforce `http/https`, allowlist hostnames, re-resolve DNS/IP to block private ranges.\n* Set timeouts (AbortSignal) and limit redirects.\n\n---\n\n### NEXT-REDIRECT-001: Prevent open redirects (including auth flows)\n\nSeverity: Low\n\nRequired:\n\n* MUST validate redirect targets derived from untrusted input (e.g., `next`, `redirect`, `returnTo`).\n* SHOULD prefer redirecting only to same-site relative paths.\n* MUST validate any absolute URL against an allowlist.\n* MUST ensure urls are `http` or `https:` schema, disallowing `javascript:` schema\n\nInsecure patterns:\n\n* `redirect(searchParams.get('next')!)`\n* `NextResponse.redirect(new URL(req.nextUrl.searchParams.get('to')!, req.url))` without checks\n\nDetection hints:\n\n* Search for `redirect(` (server components/actions) and `NextResponse.redirect`.\n* Search for `res.redirect(` in API Routes. ([Next.js][3])\n\nFix:\n\n* Only allow relative paths (`/path`) and reject protocol-relative (`//evil.com`) or absolute URLs.\n* If invalid, fall back to a safe default (home/dashboard).\n\n---\n\n### NEXT-CORS-001: CORS must be explicit and least-privilege\n\nSeverity: Medium (High if misconfigured with credentials)\n\nRequired:\n\n* If CORS is not needed, MUST keep it disabled.\n* Next.js API Routes do not set CORS headers by default, meaning they are same-origin by default; only enable CORS when you truly need it. ([Next.js][3])\n* If enabling CORS:\n\n  * MUST allowlist trusted origins (no reflection of arbitrary Origin)\n  * MUST be careful with credentialed requests (cookies); never combine broad origins with credentials.\n  * SHOULD restrict methods and headers.\n\nInsecure patterns:\n\n* `Access-Control-Allow-Origin: *` with `Access-Control-Allow-Credentials: true`\n* Reflecting `Origin` without validation.\n\nDetection hints:\n\n* Search for `Access-Control-Allow-Origin`, `cors`, “CORS” middleware/wrappers.\n* Review preflight `OPTIONS` handlers.\n\nFix:\n\n* Implement strict origin allowlist and minimal methods/headers.\n* Ensure cookies aren’t exposed cross-origin unless necessary and reviewed.\n\n---\n\n### NEXT-WEBHOOK-001: Webhook endpoints MUST verify authenticity using the raw body\n\nSeverity: Medium\n\nRequired:\n\n* MUST verify webhook signatures using the **raw request body** (not a re-serialized parsed object).\n* Next.js notes a use case for disabling body parsing is verifying the raw body of a webhook request. ([Next.js][3])\n\nInsecure patterns:\n\n* Verifying webhook signatures over `JSON.stringify(req.body)` (can change formatting).\n* Accepting webhooks with no signature verification and no allowlist.\n\nDetection hints:\n\n* Find webhook endpoints (`/api/webhook`, `/app/api/**/webhook`).\n* Check whether they use raw body verification.\n\nFix:\n\n* Disable Next.js automatic body parsing only for those webhook routes, read raw bytes safely, verify signature, then parse.\n\n---\n\n### NEXT-INJECT-001: Prevent SQL injection (use parameterized queries / ORM)\n\nSeverity: High\n\nRequired:\n\n* MUST use parameterized queries or an ORM that parameterizes under the hood.\n* MUST NOT build SQL by string concatenation / template strings with untrusted input.\n\nInsecure patterns:\n\n* ``db.query(`SELECT * FROM users WHERE id = ${id}`)``\n* `\"WHERE name = '\" + user + \"'\"`\n\nDetection hints:\n\n* Grep for `SELECT`, `INSERT`, `UPDATE`, `DELETE` strings.\n* Trace untrusted input (`params`, `searchParams`, `req.query`, `req.body`, `request.json()`) into DB calls.\n\nFix:\n\n* Use prepared statements / ORM query APIs.\n* Validate and coerce types before querying.\n\n---\n\n### NEXT-INJECT-002: Prevent OS command injection and unsafe subprocess use\n\nSeverity: Critical to High\n\nRequired:\n\n* MUST avoid executing OS commands with attacker-controlled input.\n* If subprocess is necessary:\n\n  * MUST pass args as an array (not a single shell string)\n  * MUST NOT use `shell: true` with attacker-influenced strings\n  * SHOULD use strict allowlists for any variable component\n\nInsecure patterns:\n\n* `exec(\"convert \" + filename)`\n* `spawn(\"bash\", [\"-c\", userInput])`\n* `spawn(userInput, [\"foo\"])`\n\nDetection hints:\n\n* Search for `child_process`, `exec`, `spawn`, `shell: true`.\n\nFix:\n\n* Use library APIs instead of shell commands.\n* Hard-code commands and allowlist validated parameters (and use `--` to separate flags where supported).\n\n---\n\n### NEXT-INJECT-003: Avoid dynamic code execution and unsafe deserialization\n\nSeverity: High to Critical\n\nRequired:\n\n* MUST NOT use `eval`, `new Function`, `vm.runIn*` on untrusted strings.\n* MUST treat deserializing complex formats (YAML, XML, custom serialization) as risky; use safe parsers and strict schemas.\n\nInsecure patterns:\n\n* `eval(req.body.code)`\n* Parsing YAML from user input with a non-safe schema.\n\nDetection hints:\n\n* Search for `eval(`, `new Function`, `vm.`, `require(` with non-literals.\n* Search for `js-yaml`, XML parsers, custom serializer usage on untrusted input.\n\nFix:\n\n* Remove dynamic execution; use safe interpreters or strict parsers.\n* Validate and constrain input.\n\n---\n\n### NEXT-LOG-001: Logging MUST NOT leak secrets or sensitive headers\n\nSeverity: Medium\n\nRequired:\n\n* MUST NOT log:\n\n  * `Authorization` headers\n  * cookies / session tokens\n  * request bodies containing credentials\n  * environment variables or configuration dumps\n* SHOULD implement structured logging with redaction.\n\nInsecure patterns:\n\n* `console.log(req.headers)` in auth endpoints\n* `console.log(process.env)` in server code\n\nDetection hints:\n\n* Search for `console.log(`, `logger.info(`, `debug(` in server routes/actions.\n* Check for logs of headers/cookies/body.\n\nFix:\n\n* Redact sensitive fields; log only what is needed for debugging.\n* Use safe error messages for clients; keep detail server-side only.\n\n---\n\n### NEXT-ERROR-001: Error handling MUST avoid leaking implementation details in production\n\nSeverity: Low\n\nRequired:\n\n* MUST not expose stack traces or internal error details to end users in production.\n* Ensure production mode behavior (Next.js production error handling differs from dev). ([Next.js][6])\n\nInsecure patterns:\n\n* Returning `err.stack` in JSON responses.\n* Showing detailed exception data to unauthenticated users.\n\nDetection hints:\n\n* Search for `res.status(500).json(err)` or `return Response.json(err)`.\n* Verify error responses are sanitized.\n\nFix:\n\n* Return generic error messages to clients; log details server-side with redaction.\n\n---\n\n### NEXT-PROXY-001: Proxy/Middleware must not introduce header smuggling or unsafe header forwarding\n\nSeverity: Medium\n\nRequired:\n\n* MUST be careful when copying/forwarding request headers upstream:\n\n  * Do not forward attacker-controlled `x-forwarded-*` headers unless you have a trusted proxy chain.\n  * Do not forward `Authorization`/cookies to unrelated outbound services.\n* Next.js Proxy patterns often mutate headers; ensure this doesn’t create security issues.\n\nInsecure patterns:\n\n* Blindly cloning all request headers to an outbound `fetch()` call.\n* Trusting `x-forwarded-host` or `host` to construct sensitive absolute URLs without allowlisting.\n\nDetection hints:\n\n* Search `headers()` and `request.headers` usage (especially for URL building). ([Next.js][4])\n* Search Proxy/Middleware for header rewrites.\n\nFix:\n\n* Allowlist forwarded headers explicitly.\n* Validate hostnames before using them to build callback URLs or redirects.\n\n---\n\n### NEXT-HOST-001: Host/Origin-derived URL construction MUST be allowlisted\n\nSeverity: Medium\n\nRequired:\n\n* MUST NOT generate security-sensitive absolute URLs (password reset links, OAuth callback URLs, email verification links) directly from unvalidated `Host` headers.\n* For Server Actions, Origin/Host matching is part of CSRF mitigation; do not weaken it. ([Next.js][5])\n\nInsecure patterns:\n\n* `const base = \"https://\" + request.headers.get(\"host\")`\n* Using unvalidated `x-forwarded-host` for absolute URL generation.\n\nDetection hints:\n\n* Grep for `.get('host')`, `.get('x-forwarded-host')`, and absolute URL building.\n* Review auth-related email link generation code.\n\nFix:\n\n* Use a configured, allowlisted canonical app origin (e.g., `APP_ORIGIN=https://example.com`).\n* Allowlist hostnames; fail closed.\n\n---\n\n### NEXT-DOS-001: Rate limiting and resource controls MUST exist for abuse-prone endpoints\n\nSeverity: Medium\n\nRequired:\n\n* SHOULD implement rate limiting/throttling for:\n\n  * login, password reset, signup\n  * expensive Server Actions\n  * webhook ingestion\n* MUST implement request size limits (see NEXT-LIMITS-001).\n* If self-hosting, MUST rely on reverse proxy for additional protections. ([Next.js][8])\n\nInsecure patterns:\n\n* No throttling on login/reset endpoints.\n* Expensive actions callable without auth or with unlimited frequency.\n\nDetection hints:\n\n* Identify auth endpoints and check for rate limiting.\n* Search for “send email”, “charge”, “generate report” flows.\n\nFix:\n\n* Add edge rate limiting and app-level user/IP throttles.\n* Add job queues for heavy work; return 202 when appropriate.\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* Production misconfig:\n\n  * `next dev`, `NODE_ENV=development`, dev-only start commands ([Next.js][7])\n* Secrets exposure:\n\n  * `.env` committed, `NEXT_PUBLIC_` on sensitive variables ([Next.js][7])\n  * `process.env` used in `\"use client\"` modules\n* Auth coverage:\n\n  * `app/**/route.ts` or `pages/api/**` with no auth checks ([Next.js][1])\n  * `\"use server\"` actions with DB writes and no authz ([Next.js][6])\n  * `proxy.ts` / `middleware.ts` matchers that exclude sensitive routes ([Next.js][12])\n* CSRF:\n\n  * cookie-auth POST/PUT/PATCH/DELETE with no token/origin checks\n  * `serverActions.allowedOrigins` too broad ([Next.js][5])\n* XSS:\n\n  * `dangerouslySetInnerHTML`, raw HTML markdown rendering\n  * missing CSP / overly permissive CSP ([Next.js][7])\n* Caching/data leak:\n\n  * `dynamic = 'force-static'` on sensitive GET handlers ([Next.js][1])\n  * `use cache`, `cacheLife`, `unstable_cache` around user-specific data ([Next.js][1])\n* Files:\n\n  * writing uploads under `public/`\n  * `fs.readFile` / `path.join` with request input\n* SSRF:\n\n  * `fetch(userProvidedUrl)` from Route Handlers / Server Actions\n* Redirect:\n\n  * `redirect(searchParams.get('next'))`, `NextResponse.redirect(...)`, `res.redirect(req.query.next)` ([Next.js][3])\n* CORS:\n\n  * wildcard origins, origin reflection, credentials + broad origins ([Next.js][3])\n* Limits:\n\n  * API routes with `bodyParser: false` and no raw-body verification for webhooks ([Next.js][3])\n  * `serverActions.bodySizeLimit` raised without justification ([Next.js][5])\n* Dependency hygiene:\n\n  * old `next` versions that conflict with support policy/advisories ([Next.js][10])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (HTML/DOM, SQL, subprocess, files, redirect, outbound HTTP)\n* protective controls present (schema validation, allowlists, middleware/proxy checks, authz helpers, edge protections)\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary framework documentation (Next.js):\n\n* Next.js Docs: Installation (system requirements / Node version) — `https://nextjs.org/docs/app/getting-started/installation`\n* Next.js Docs: Route Handlers — `https://nextjs.org/docs/app/getting-started/route-handlers`\n* Next.js Docs: API Routes (Pages Router) — `https://nextjs.org/docs/pages/building-your-application/routing/api-routes`\n* Next.js Docs: Environment Variables — `https://nextjs.org/docs/pages/guides/environment-variables`\n* Next.js Docs: Data Security — `https://nextjs.org/docs/app/guides/data-security`\n* Next.js Docs: Content Security Policy — `https://nextjs.org/docs/app/guides/content-security-policy`\n* Next.js Docs: Proxy — `https://nextjs.org/docs/app/getting-started/proxy`\n* Next.js Docs: `serverActions.allowedOrigins` and `serverActions.bodySizeLimit` — `https://nextjs.org/docs/app/api-reference/config/next-config-js/serverActions`\n* Next.js Docs: `cookies()` — `https://nextjs.org/docs/app/api-reference/functions/cookies`\n* Next.js Docs: `headers()` — `https://nextjs.org/docs/app/api-reference/functions/headers`\n* Next.js Docs: Self-hosting (reverse proxy guidance) — `https://nextjs.org/docs/pages/guides/self-hosting`\n* Next.js Docs: Support policy (supported versions/LTS) — `https://nextjs.org/docs/support-policy`\n\nNext.js security guidance & advisories:\n\n* Next.js Blog: How to think about security in Next.js — `https://nextjs.org/blog/security-nextjs-server-components-actions`\n* GitHub Security Advisory: Next.js DoS via Server Components / Server Actions (CVE-2026-23864) — `https://github.com/advisories/GHSA-fq29-rrrv-cq2m`\n* Next.js Blog: Security update (example security advisory context) — `https://nextjs.org/blog/security-update`\n\nGeneral web security references (recommended baseline):\n\n* OWASP Cheat Sheet Series (CSRF, Session Management, XSS Prevention, SSRF Prevention, File Upload, HTTP Headers) — `https://cheatsheetseries.owasp.org/`\n\n[1]: https://nextjs.org/docs/app/getting-started/route-handlers \"Getting Started: Route Handlers | Next.js\"\n[2]: https://nextjs.org/docs/app/getting-started/deploying?utm_source=chatgpt.com \"Getting Started: Deploying\"\n[3]: https://nextjs.org/docs/pages/building-your-application/routing/api-routes \"Routing: API Routes | Next.js\"\n[4]: https://nextjs.org/docs/app/api-reference/functions/headers \"Functions: headers | Next.js\"\n[5]: https://nextjs.org/docs/app/api-reference/config/next-config-js/serverActions \"next.config.js: serverActions | Next.js\"\n[6]: https://nextjs.org/blog/security-nextjs-server-components-actions \"How to Think About Security in Next.js | Next.js\"\n[7]: https://nextjs.org/docs/pages/guides/environment-variables \"Guides: Environment Variables | Next.js\"\n[8]: https://nextjs.org/docs/pages/guides/self-hosting?utm_source=chatgpt.com \"Guides: Self-Hosting\"\n[9]: https://nextjs.org/docs/app/api-reference/functions/cookies \"Functions: cookies | Next.js\"\n[10]: https://nextjs.org/blog/next-16?utm_source=chatgpt.com \"Next.js 16\"\n[11]: https://github.com/vercel/next.js/security/advisories/GHSA-9g9p-9gw9-jx7f?utm_source=chatgpt.com \"Denial of Service in Image Optimizer · Advisory\"\n[12]: https://nextjs.org/docs/pages/guides/authentication \"Guides: Authentication | Next.js\"\n","core/skills/builtin/security-best-practices/references/javascript-typescript-react-web-frontend-security.md":"# React (JavaScript/TypeScript) Web Security Spec (React 19.x, TypeScript 5.x)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new React code.\n2. **Security review / vulnerability hunting** in existing React code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, OAuth client secrets, private keys, session cookies, JWTs, signing keys).\n\n  * Frontend note: anything shipped to the browser is observable by end users and attackers (view-source, devtools, proxies); never treat client code or “env vars in the bundle” as secret. ([create-react-app.dev][1])\n* MUST NOT “fix” security by disabling protections (e.g., turning off CSP to “make it work”, adding `unsafe-inline`/`unsafe-eval` without a documented, constrained plan, disabling CSRF protections when using cookies, widening CORS, skipping sanitization, or “temporary” bypasses that ship). ([OWASP Cheat Sheet Series][2])\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and configuration values that justify the claim.\n* MUST treat uncertainty honestly: if a protection might exist in infra (CDN/WAF/reverse proxy), report it as “not visible in app code; verify via runtime headers / edge config”.\n* MUST assume any data that crosses a trust boundary (URL, storage, network, postMessage, third-party scripts) can be attacker-influenced unless proven otherwise (see §2.1).\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new React code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default APIs and proven libraries over custom security code.\n* MUST avoid introducing new risky sinks (raw HTML insertion, direct DOM sinks like `innerHTML`, dynamic code execution, untrusted redirects/navigation, third‑party script injection, unsafe token storage, etc.). ([MDN Web Docs][3])\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a React repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. App entrypoints, build tooling (Vite/Webpack/CRA/Next), deployment configs, CDN/static hosting config.\n2. Secrets & configuration exposure (env vars, runtime config injection, source maps).\n3. Rendering of untrusted data (XSS/DOM XSS), especially `dangerouslySetInnerHTML`, markdown/HTML renderers, URL attributes.\n4. Direct DOM usage and dangerous JS execution (`innerHTML`, `eval`, `new Function`, `document.write`, etc.).\n5. Auth & session patterns (token storage, cookies, CSRF interactions, OAuth flows).\n6. Network layer (axios/fetch wrappers, dynamic base URLs, credentialed requests, data exfil risks).\n7. Navigation & redirect handling (open redirects, `window.location`, `target=_blank`, `window.open`).\n8. Third-party scripts/tags/analytics and integrity controls (CSP, SRI).\n9. Service worker/PWA behavior (HTTPS, caching rules, update strategy).\n10. Security headers posture (CSP, clickjacking, nosniff, referrer policy) in app or at the edge. ([OWASP Cheat Sheet Series][2])\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nExamples include:\n\n* URL-derived data: `window.location`, query params, hash fragments, route params.\n* Any data from browser storage: `localStorage`, `sessionStorage`, `IndexedDB` (including data previously written by the app—because XSS or extensions can tamper with it). ([OWASP Cheat Sheet Series][4])\n* Any data from cross-window messaging: `window.postMessage` payloads. ([OWASP Cheat Sheet Series][4])\n* Any data from remote APIs, webhooks proxied to the client, GraphQL responses, CMS content, feature flag services.\n* Any persisted user content (profiles, comments, rich text, markdown) rendered in the UI.\n* Any data produced by third-party scripts or tag managers (treat as untrusted unless strongly controlled). ([OWASP Cheat Sheet Series][5])\n\n### 2.2 State-changing request (frontend perspective)\n\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook), or initiate privileged actions.\n\nFrontend-specific note:\n\n* State changes are often triggered by `fetch/axios` calls or form submissions. If authentication is cookie-based, these calls can be CSRF-relevant (§4 REACT-CSRF-001). ([OWASP Cheat Sheet Series][6])\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + component/function + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common React frontend misconfigurations.\n\n### 3.1 Production build and configuration hygiene (MUST)\n\n* MUST ship a production build (minified, no dev-only overlays/tools, correct mode flags).\n* MUST ensure build-time configuration does not embed secrets into the shipped JS/HTML/CSS. Build-time “environment variables” are not secret; treat them as public. ([create-react-app.dev][1])\n* SHOULD treat source maps as sensitive operational artifacts:\n\n  * Either don’t publish them publicly, or publish them only where intended (e.g., behind auth or to an error-reporting provider), because they can reveal code structure and internal URLs.\n\n### 3.2 Browser-enforced protections (SHOULD, but baseline expectation for modern apps)\n\n* SHOULD deploy a CSP as defense-in-depth against XSS, and keep it compatible with your React build (avoid `unsafe-inline` and `unsafe-eval` unless strictly necessary and documented). ([OWASP Cheat Sheet Series][2])\n* SHOULD use Subresource Integrity (SRI) for any third-party script/style loaded from a CDN (or self-host instead). ([MDN Web Docs][7])\n* SHOULD enable clickjacking defenses via `frame-ancestors` (CSP) and/or `X-Frame-Options`, unless embedding is an explicit product requirement. ([MDN Web Docs][8])\n\n### 3.3 High-risk features baseline (MUST if used)\n\n* If rendering any user-provided HTML/markdown/rich text:\n\n  * MUST sanitize before insertion and avoid raw DOM sinks. ([OWASP Cheat Sheet Series][9])\n* If using service workers / PWA:\n\n  * MUST serve over HTTPS and implement a safe caching/update strategy (service workers are powerful request/response proxies). ([MDN Web Docs][10])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### REACT-CONFIG-001: Never embed secrets in the client bundle (env vars are public)\n\nSeverity: Critical (if secrets exposed)\n\nRequired:\n\n* MUST NOT place secrets in React code, in `public/` assets, or in build-time environment variables intended for client consumption.\n* MUST assume any value available to the React app at runtime can be extracted by an attacker.\n\nInsecure patterns:\n\n* Using build-time env vars for secrets:\n\n  * `process.env.REACT_APP_*` containing private keys or credentials.\n  * `import.meta.env.VITE_*` containing secrets.\n* Hard-coded secrets in JS/TS, `.env` committed, or secrets in `public/config.json` served to all users.\n\nDetection hints:\n\n* Search for:\n\n  * `REACT_APP_`, `VITE_`, `NEXT_PUBLIC_`, `process.env.`, `import.meta.env.`\n  * `apiKey`, `secret`, `token`, `private`, `password`, `client_secret`\n* Inspect `public/` for runtime config JSON.\n\nFix:\n\n* Move secrets server-side (API, BFF, serverless function).\n* Use a backend to mint short-lived, scoped tokens if the browser needs to call third-party APIs.\n\nNotes:\n\n* CRA explicitly warns not to store secrets and notes env vars are embedded into the build and visible to anyone inspecting files. ([create-react-app.dev][1])\n* Vite explicitly notes that variables exposed to client code end up in the client bundle and should not contain sensitive info. ([vitejs][11])\n\n---\n\n### REACT-XSS-001: Do not use `dangerouslySetInnerHTML` with untrusted content (sanitize or avoid)\n\nSeverity: High (Only if you can prove attacker-controlled HTML reaches it)\n\nRequired:\n\n* MUST avoid `dangerouslySetInnerHTML` unless absolutely necessary.\n* If it must be used:\n\n  * MUST sanitize untrusted HTML with a proven sanitizer (e.g., DOMPurify) and an allowlist-oriented configuration.\n  * MUST keep the sanitization logic centralized and heavily reviewed.\n  * SHOULD add a CSP and consider Trusted Types (see REACT-TT-001).\n\nInsecure patterns:\n\n* `<div dangerouslySetInnerHTML={{ __html: userHtml }} />` where `userHtml` is from API/URL/storage.\n* “Sanitization” done with regexes, ad-hoc stripping, or incomplete allowlists.\n\nDetection hints:\n\n* Grep: `dangerouslySetInnerHTML`, `__html:`\n* Trace the origin of the HTML string (API/CMS/URL/localStorage).\n\nFix:\n\n* Replace with safe rendering:\n\n  * Render structured data as React elements/components instead of HTML strings.\n  * If rich text is required, sanitize with DOMPurify (or equivalent) and render the sanitized output.\n* Add CSP; remove dangerous sinks where possible.\n\nNotes:\n\n* React explicitly warns that `dangerouslySetInnerHTML` is dangerous and can introduce XSS if misused. ([React][12])\n* OWASP explicitly calls out React’s `dangerouslySetInnerHTML` without sanitization as a common framework “escape hatch” pitfall. ([OWASP Cheat Sheet Series][9])\n* DOMPurify describes itself as an XSS sanitizer for HTML/SVG/MathML. ([GitHub][13])\n\n---\n\n### REACT-XSS-002: Rely on React’s escaping-by-default behavior; do not bypass it\n\nSeverity: High (when bypassed)\n\nRequired:\n\n* MUST render untrusted strings via normal JSX interpolation (`{value}`) and React props, which are escaped by default.\n* MUST NOT build HTML strings from untrusted data and then inject them into the DOM via any means.\n* SHOULD treat any “escape hatch” as high risk and require review.\n\nInsecure patterns:\n\n* Converting untrusted text into HTML and injecting it:\n\n  * `element.innerHTML = userValue`\n  * `document.write(userValue)`\n  * `insertAdjacentHTML(..., userValue)`\n\nDetection hints:\n\n* Grep for DOM sinks: `innerHTML`, `outerHTML`, `insertAdjacentHTML`, `document.write`, `DOMParser`, `createContextualFragment`.\n\nFix:\n\n* Render text content through React (JSX) so it is escaped.\n* If you truly need HTML, sanitize and apply REACT-XSS-001 + REACT-TT-001.\n\nNotes:\n\n* React documentation (JSX) states that React DOM escapes values embedded in JSX before rendering to help prevent injection attacks. ([React][14])\n\n---\n\n### REACT-DOM-001: Avoid DOM XSS injection sinks in React code (use safe alternatives)\n\nSeverity: High\n\nRequired:\n\n* MUST avoid direct DOM injection sinks, even outside React rendering, unless strongly controlled.\n* If a DOM sink is required:\n\n  * MUST ensure inputs are trusted/validated/sanitized.\n  * SHOULD enforce Trusted Types (REACT-TT-001).\n\nInsecure patterns:\n\n* `someEl.innerHTML = untrusted`\n* `document.write(untrusted)`\n* `new DOMParser().parseFromString(untrusted, 'text/html')` followed by insertion\n\nDetection hints:\n\n* Grep for: `innerHTML`, `outerHTML`, `document.write`, `DOMParser`, `Range().createContextualFragment`, `insertAdjacentHTML`\n\nFix:\n\n* Prefer:\n\n  * `textContent` for text insertion.\n  * React rendering rather than manual DOM manipulation.\n  * A vetted sanitizer for any required HTML parsing.\n\nNotes:\n\n* Trusted Types documentation defines HTML sinks like `Element.innerHTML` and `document.write()` as injection sinks that can execute script when given attacker-controlled input. ([MDN Web Docs][3])\n* OWASP HTML5 guidance recommends using `textContent` instead of `innerHTML` for assigning untrusted data. ([OWASP Cheat Sheet Series][4])\n\n---\n\n### REACT-URL-001: Validate and constrain untrusted URLs used in `href`, `src`, navigation, and redirects\n\nSeverity: High Only when you can prove they are attacker controlled\n\nRequired:\n\n* MUST treat any URL derived from untrusted input as dangerous.\n* MUST allowlist schemes and (when applicable) hosts:\n\n  * Typically allow only `https:` (and maybe `http:` for localhost/dev) and relative URLs for in-app navigation.\n  * MUST explicitly block `javascript:` and dangerous `data:` uses unless you have specialized validation and a clear use case.\n* SHOULD prefer same-site relative paths (e.g., `/settings`) over absolute URLs.\n* MUST validate “returnTo/next/redirect” parameters (see REACT-REDIRECT-001).\n\nInsecure patterns:\n\n* `<img src={userProvidedUrl}>...` (can be used for tracking / data exfil; also risky if used for scripts/iframes)\n* `window.location = next`\n* `navigate(next)` where `next` comes from query params without validation\n\nDetection hints:\n\n* Search for:\n\n  * `href={`, `src={`, `window.location`, `location.href`, `window.open`, `navigate(`, `redirectTo`, `returnTo`, `next=`\n* Track whether the value is derived from URL/query/storage/API.\n\nFix:\n\n* Implement a shared `safeUrl()` utility:\n\n  * Parse with `new URL(value, base)`\n  * Enforce scheme allowlist and host allowlist (or enforce same-origin)\n  * For redirects: allow only relative paths (starting with `/`) or a strict allowlist of absolute origins.\n* Fall back to a safe default when validation fails.\n\nNotes:\n\n* OWASP explicitly notes React’s `dangerouslySetInnerHTML` risk and also states React cannot safely handle `javascript:` or `data:` URLs without specialized validation. ([OWASP Cheat Sheet Series][9])\n\n---\n\n### REACT-MARKUP-001: Markdown / rich text rendering must be configured safely\n\nSeverity: Medium\n\nRequired:\n\n* MUST assume markdown/rich text can be attacker-controlled if it comes from users or CMS.\n* MUST ensure raw HTML is not rendered unless sanitized.\n* SHOULD prefer markdown renderers that:\n\n  * Do not allow raw HTML by default, or\n  * Can be configured to disallow raw HTML, or\n  * Sanitize HTML output before rendering.\n\nInsecure patterns:\n\n* Markdown rendering with “raw HTML passthrough” enabled (e.g., options/plugins that allow HTML).\n* Rendering user-provided SVG/MathML/HTML inline without sanitization.\n\nDetection hints:\n\n* Search for common libraries and risky options:\n\n  * `marked`, `markdown-it`, `react-markdown`, `rehype-raw`, `sanitize: false`, `allowDangerousHtml`, etc.\n* Look for `dangerouslySetInnerHTML` used with “markdown output”.\n\nFix:\n\n* Disable raw HTML passthrough.\n* Sanitize output with a proven sanitizer (e.g., DOMPurify) before rendering.\n\nNotes:\n\n* OWASP XSS guidance emphasizes that framework escape hatches require output encoding and/or HTML sanitization. ([OWASP Cheat Sheet Series][9])\n\n---\n\n### REACT-TT-001: Use Trusted Types (with CSP) to harden DOM XSS sinks where feasible\n\nSeverity: Low\n\nRequired:\n\n* SHOULD consider enabling Trusted Types in report-only mode first, then enforce once violations are addressed.\n* SHOULD centralize Trusted Types policies and treat them as high-risk code requiring review.\n* MUST NOT create permissive policies that simply “pass through” untrusted strings.\n\nInsecure patterns:\n\n* A Trusted Types policy that returns the raw string without sanitization for HTML sinks.\n* Many scattered policies across the codebase (hard to audit).\n\nDetection hints:\n\n* Search for:\n\n  * `trustedTypes.createPolicy`\n  * CSP directives: `require-trusted-types-for`, `trusted-types`\n* Search for remaining DOM sinks (REACT-DOM-001).\n\nFix:\n\n* Implement a small number of tightly scoped policies:\n\n  * HTML policy uses sanitizer (DOMPurify or equivalent).\n  * Script URL policy uses strict allowlists.\n* Run in report-only mode, fix violations, then enforce.\n\nNotes:\n\n* MDN describes Trusted Types as a way to ensure input is transformed (commonly sanitized) before being passed to injection sinks, and highlights HTML sinks (`innerHTML`, `document.write`) and JS URL sinks (`script.src`). ([MDN Web Docs][3])\n* The W3C Trusted Types spec frames this as reducing DOM XSS risk by locking down sinks to typed values created by reviewed policies. ([W3C][15])\n\n---\n\n### REACT-CSP-001: Deploy and maintain a CSP as defense-in-depth (especially when rendering untrusted content)\n\nSeverity: Medium to High\n\nRequired:\n\n* SHOULD deploy CSP in production; MUST do so for apps that render untrusted content or integrate third-party scripts.\n* SHOULD avoid `unsafe-inline` and `unsafe-eval` when possible.\n* SHOULD use CSP nonces/hashes for inline scripts if needed, and keep policy realistic.\n* SHOULD use CSP to require/encourage SRI where appropriate.\n\nInsecure patterns:\n\n* No CSP at all on the app shell (SPA entry HTML).\n* CSP that relies on `unsafe-inline`/`unsafe-eval` broadly without justification.\n* `script-src *` or overly broad sources.\n\nDetection hints:\n\n* Look for CSP configuration:\n\n  * Server/CDN config, headers in `index.html` responses, or framework config.\n* If absent in repo, mark as “verify at edge”.\n\nFix:\n\n* Add CSP via HTTP response headers (preferred).\n* Start with report-only to reduce breakage, then enforce.\n\nNotes:\n\n* OWASP describes CSP as “defense in depth” against XSS and notes it can help enforce SRI even on static sites, but should not be the only defense. ([OWASP Cheat Sheet Series][2])\n\n---\n\n### REACT-SRI-001: Use Subresource Integrity (SRI) for third-party scripts and styles (or self-host)\n\nSeverity: Low\n\nRequired:\n\n* MUST treat third-party JS as equivalent to running arbitrary code in your origin.\n* If loading from a CDN or third party:\n\n  * SHOULD use SRI (`integrity=...`) and `crossorigin` where applicable.\n  * SHOULD pin exact versions (avoid “latest” URLs).\n  * SHOULD prefer self-hosting for critical code.\n\nInsecure patterns:\n\n* `<script src=\"https://cdn.example.com/lib/latest.js\"></script>` with no integrity.\n* Tag managers that dynamically load arbitrary scripts without governance.\n\nDetection hints:\n\n* Search in `public/index.html`, templates, or SSR wrappers for:\n\n  * `<script src=`, `<link rel=\"stylesheet\" href=`\n  * Tag manager snippets (GTM, Segment, etc.)\n* Identify scripts loaded dynamically in runtime JS.\n\nFix:\n\n* Add SRI hashes for stable third-party assets or self-host.\n* Apply governance controls for tag managers (see REACT-3P-001).\n\nNotes:\n\n* MDN describes SRI as a security feature enabling browsers to verify fetched resources (e.g., from a CDN) haven’t been manipulated by checking a cryptographic hash. ([MDN Web Docs][7])\n* OWASP CSP guidance notes CSP can enforce SRI and is useful even on static sites. ([OWASP Cheat Sheet Series][2])\n\n---\n\n### REACT-3P-001: Third-party JavaScript and tag managers must be minimized and governed\n\nSeverity: High\n\nRequired:\n\n* MUST minimize third-party scripts and treat each as a supply-chain risk.\n* MUST know exactly what third-party JS executes in your origin and why.\n* SHOULD implement governance:\n\n  * Review and pin versions (or mirror in-house).\n  * Restrict data access (data-layer approach).\n  * Use SRI and CSP; consider sandboxing untrusted UI in iframes where possible.\n\nInsecure patterns:\n\n* Unreviewed analytics/ads scripts running with full access to DOM, cookies, storage, and user data.\n* Tag managers that can be changed by non-engineering roles with no change control.\n\nDetection hints:\n\n* Search for common vendor snippets in HTML/JS:\n\n  * GTM, Segment, Hotjar, FullStory, etc.\n* Look for dynamic script insertion:\n\n  * `document.createElement('script')`, `.src = ...`, `.appendChild(script)`\n\nFix:\n\n* Reduce to only necessary vendors.\n* Where feasible:\n\n  * Self-host or mirror scripts.\n  * Use SRI.\n  * Limit data exposure via a controlled data layer.\n\nNotes:\n\n* OWASP notes third-party JS server compromise can inject malicious JS, and highlights risks like arbitrary code execution and disclosure of sensitive info to third parties. ([OWASP Cheat Sheet Series][5])\n\n---\n\n### REACT-AUTH-001: Token and session handling must be resilient to XSS (avoid sensitive storage in Web Storage)\n\nSeverity: Medium\n\nRequired:\n\n* SHOULD avoid storing session identifiers or long-lived tokens in `localStorage` (and generally in Web Storage) because XSS can exfiltrate them.\n* If tokens must exist client-side:\n\n  * SHOULD prefer in-memory storage with short lifetimes and refresh mechanisms.\n  * MUST scope and rotate tokens; avoid long-lived bearer tokens in persistent storage.\n* SHOULD prefer HTTPOnly cookies for session tokens when possible (requires CSRF strategy: see REACT-CSRF-001).\n\nInsecure patterns:\n\n* `localStorage.setItem('token', ...)` / `sessionStorage.setItem('token', ...)` for auth tokens.\n* Persisting refresh tokens in `localStorage`.\n* Treating data from Web Storage as trusted.\n\nDetection hints:\n\n* Grep for: `localStorage.`, `sessionStorage.`, `setItem(`, `getItem(`, `token`, `jwt`, `refresh`\n* Search auth code for “remember me” storing tokens persistently.\n\nFix:\n\n* Move to HTTPOnly cookies (server change) + CSRF protections, or use short-lived in-memory tokens.\n* Reduce token scope and lifetime.\n\nNotes:\n\n* OWASP HTML5 guidance recommends avoiding sensitive info and session identifiers in local storage and warns that a single XSS can steal all data in Web Storage. ([OWASP Cheat Sheet Series][4])\n* OAuth browser-based apps guidance discusses that tokens stored in persistent browser storage like localStorage can be accessible to malicious JS (e.g., via XSS). ([IETF Datatracker][16])\n\n---\n\n### REACT-CSRF-001: Cookie-authenticated, state-changing requests MUST be CSRF-protected\n\nSeverity: High\n\nNOTE: If the application does not use cookie based auth (using Authentication header for example), then CSRF is not a concern.\n\nRequired:\n\n* If the app relies on cookies for authentication:\n\n  * MUST protect state-changing requests (POST/PUT/PATCH/DELETE) against CSRF.\n  * SHOULD include a CSRF token mechanism (synchronizer token or double-submit cookie) or other robust pattern appropriate to the backend.\n  * SHOULD use SameSite cookies as defense-in-depth, not as the sole defense.\n\nInsecure patterns:\n\n* `fetch('/api/transfer', { method: 'POST', credentials: 'include' })` with no CSRF token/header, relying only on cookies.\n* Using GET for state-changing operations.\n\nDetection hints:\n\n* Enumerate state-changing network calls and check:\n\n  * Is `credentials: 'include'` or `withCredentials: true` used?\n  * Is a CSRF token header included (e.g., `X-CSRF-Token`)?\n* Search for “csrf” utilities; if absent, treat as suspicious.\n\nFix:\n\n* Add CSRF token flow:\n\n  * Fetch token from a safe endpoint and attach to state-changing requests.\n  * Validate server-side.\n* Keep SameSite cookies and Origin/Referer validation as defense-in-depth.\n\nNotes:\n\n* OWASP CSRF guidance explains SameSite behavior (Lax/Strict/None) as a defense-in-depth technique and why Lax is often the usability/security balance, but it is not a complete substitute for CSRF protections. ([OWASP Cheat Sheet Series][6])\n\n---\n\n### REACT-AUTHZ-001: Do not rely on frontend-only authorization\n\nSeverity: High (only if used as primary protection)\n\nRequired:\n\n* MUST treat all frontend authorization checks as UX only.\n* MUST enforce authorization on the server for any protected resource or action.\n\nInsecure patterns:\n\n* “Protected” actions hidden in UI but callable by API without server checks.\n* Client checks like `if (user.isAdmin) { showAdminPanel(); }` with no server-side enforcement.\n\nDetection hints:\n\n* Look for UI gating around sensitive actions and verify server endpoints enforce authorization.\n* In a frontend-only audit, report as “client checks are not security; verify backend”.\n\nFix:\n\n* Add/confirm server-side authorization checks.\n* Keep frontend gating only as convenience.\n\nNotes:\n\n* This is a general web app security property; React cannot protect server resources by itself.\n\n---\n\n### REACT-NET-001: Prevent data exfiltration and credential leakage via dynamic outbound requests\n\nSeverity: Medium to High\n\nRequired:\n\n* MUST avoid making authenticated requests to attacker-controlled origins.\n* SHOULD avoid allowing user input to control request destination (scheme/host/port).\n* SHOULD centralize network clients (fetch/axios) with:\n\n  * fixed `baseURL` (or strict allowlist),\n  * strict handling of redirects,\n  * explicit `credentials` usage.\n\nInsecure patterns:\n\n* `fetch(userProvidedUrl, { credentials: 'include' })`\n* `axios.create({ baseURL: userProvidedBase })`\n* “URL fetch/preview” features in the client that hit arbitrary domains with sensitive headers.\n\nDetection hints:\n\n* Search for `fetch(` / `axios(` where the first argument or `baseURL` is derived from:\n\n  * query params, localStorage, API responses, postMessage\n* Search for `credentials: 'include'`, `withCredentials: true`.\n\nFix:\n\n* Enforce destination allowlists; disallow cross-origin requests unless explicitly required.\n* Strip credentials/Authorization headers for any non-allowlisted destination.\n\nNotes:\n\n* Even if the browser limits some cross-origin behavior, leaking tokens/headers to untrusted endpoints is still a common failure mode.\n\n---\n\n### REACT-REDIRECT-001: Prevent open redirects and untrusted navigation\n\nSeverity: Medium\n\nRequired:\n\n* MUST validate redirect/navigation targets derived from untrusted input (`next`, `returnTo`, `redirect`).\n* SHOULD only allow same-site relative paths, or a strict allowlist of trusted origins for absolute URLs.\n\nInsecure patterns:\n\n* `window.location.href = new URLSearchParams(location.search).get('next')`\n* `navigate(next)` where `next` comes from query params.\n\nDetection hints:\n\n* Search for: `next`, `returnTo`, `redirect`, `window.location`, `navigate(`\n* Trace origin of the redirect target.\n\nFix:\n\n* Only allow relative paths (`/^\\/[^\\s]*$/`) or allowlisted origins.\n* Fall back to a safe default (e.g., `/`) when invalid.\n\nNotes:\n\n* Open redirects are frequently used in phishing and can undermine SSO/OAuth flows.\n\n---\n\n### REACT-SW-001: Service workers are high-privilege; require HTTPS and safe caching/update rules\n\nSeverity: Medium\n\nRequired:\n\n* MUST serve service workers over HTTPS (except `localhost` dev), and deploy only in secure contexts.\n* MUST avoid caching sensitive authenticated API responses unless explicitly designed and threat-modeled.\n* SHOULD implement safe update strategy (prompt reload, versioned caches, remove old caches on activate).\n\nInsecure patterns:\n\n* Registering a service worker for an authenticated app and caching “everything” indiscriminately.\n* Long-lived caches containing PII or user-specific content shared across accounts.\n\nDetection hints:\n\n* Search for:\n\n  * `navigator.serviceWorker.register`\n  * `workbox`, `precacheAndRoute`, custom `fetch` handlers\n* Inspect caching patterns (`caches.open`, `cache.put`, `respondWith`).\n\nFix:\n\n* Restrict caching to static assets only (JS/CSS/images) unless you have a designed offline model.\n* Ensure cache keys are user-scoped if user-specific data must be cached.\n* Provide a clear update mechanism.\n\nNotes:\n\n* MDN notes service workers require HTTPS for security reasons and act like a proxy for requests/responses. ([MDN Web Docs][10])\n* “Secure contexts” exist to prevent MITM attackers from accessing powerful APIs; service workers are an example of such a powerful feature. ([MDN Web Docs][18])\n\n---\n\n### REACT-HEADERS-001: Ensure essential security headers are set for the React app shell (app or edge)\n\nSeverity: Medium\n\nRequired (typical SPA served from an origin):\n\n* SHOULD set:\n\n  * CSP (`Content-Security-Policy`)\n  * `X-Content-Type-Options: nosniff`\n  * Clickjacking protection (`frame-ancestors` in CSP and/or `X-Frame-Options`)\n  * `Referrer-Policy`\n  * `Permissions-Policy` as appropriate\n* MUST ensure these are set somewhere (CDN/edge/server), even if not in repo.\n\nInsecure patterns:\n\n* No security headers anywhere (app or edge).\n* CSP missing on apps that render untrusted content or use third-party scripts.\n\nDetection hints:\n\n* Check server/CDN config in repo (nginx, Cloudflare, Vercel config, etc.).\n* If absent, flag as “verify at runtime/edge”.\n\nFix:\n\n* Set headers centrally at the edge.\n* Keep CSP realistic and iterative (report-only → enforce).\n\nNotes:\n\n* MDN clickjacking guidance discusses defenses including `X-Frame-Options` and CSP `frame-ancestors`. ([MDN Web Docs][8])\n* OWASP CSP guidance explains delivery via response headers and recommends headers as the preferred mechanism. ([OWASP Cheat Sheet Series][2])\n\n---\n\n### REACT-POSTMSG-001: `postMessage` must validate origin and treat payload as untrusted data\n\nSeverity: Medium to High (depends on what messages can do)\n\nRequired:\n\n* MUST specify exact `targetOrigin` when sending messages (not `*`) unless there is a strict reason.\n* MUST validate `event.origin` on receipt and validate message shape.\n* MUST NOT evaluate message data as code or insert it into the DOM as HTML.\n\nInsecure patterns:\n\n* `window.postMessage(data, '*')` to unknown targets.\n* Receiving:\n\n  * `window.addEventListener('message', (e) => { eval(e.data) })`\n  * `element.innerHTML = e.data`\n\nDetection hints:\n\n* Search: `postMessage(`, `addEventListener('message'`\n* Check for origin checks and safe handling.\n\nFix:\n\n* Add strict origin allowlists and schema validation (e.g., zod).\n* Treat message payload strictly as data; render safely via React.\n\nNotes:\n\n* OWASP HTML5 guidance recommends specifying expected origin for `postMessage`, checking sender origin, validating data, and avoiding eval/innerHTML with message content. ([OWASP Cheat Sheet Series][4])\n\n---\n\n### REACT-FILE-001: File uploads and previews must not create client-side active content vulnerabilities\n\nSeverity: Medium (can be High if stored-XSS possible)\n\nRequired:\n\n* MUST treat user-uploaded files and previews as potentially malicious.\n* MUST NOT render uploaded HTML/SVG/other active content inline unless sanitized and explicitly required.\n* SHOULD validate file types client-side for UX, but MUST rely on server-side validation for security.\n\nInsecure patterns:\n\n* Rendering user-uploaded HTML as content.\n* Inline rendering of untrusted SVG/HTML via `dangerouslySetInnerHTML` or `<iframe srcdoc=...>` without sanitization.\n\nDetection hints:\n\n* Search for upload components and preview logic:\n\n  * `input type=\"file\"`, `FileReader`, `URL.createObjectURL`, `<iframe>`, `<object>`, `<embed>`.\n* Trace where uploaded content is later displayed.\n\nFix:\n\n* Restrict accepted types, sanitize where needed, and prefer download/attachment flows for risky types.\n* Ensure server enforces the real policy (type checking, renaming, scanning, storing outside webroot).\n\nNotes:\n\n* OWASP file upload guidance highlights allowlisting extensions, validating file type, generating filenames, limiting size, storing outside webroot, and considering “client-side active content (XSS, CSRF, etc.)” when files are publicly retrievable. ([OWASP Cheat Sheet Series][19])\n\n---\n\n### REACT-SUPPLY-001: Dependency and supply-chain hygiene (frontend + build tooling)\n\nSeverity: Low\n\nRequired:\n\n* MUST use a lockfile and enforce reproducible installs in CI.\n* SHOULD regularly audit dependencies and respond quickly to advisories for:\n\n  * React, react-dom, router libs, build tooling (Vite/Webpack), sanitizers, auth libs, etc.\n* SHOULD reduce exposure to install-time script attacks and typosquatting risk.\n\nAudit focus:\n\n* CI should use `npm ci` (or Yarn frozen lockfile / pnpm equivalent) to prevent drift.\n* Use vulnerability scanning (`npm audit`, GitHub Dependabot/alerts, etc.).\n\nInsecure patterns:\n\n* No lockfile or lockfile ignored in CI.\n* `npm install` in CI producing non-reproducible builds.\n* Unpinned or unreviewed high-risk deps; sudden major updates without review.\n* Blindly running install scripts from third-party packages.\n\nDetection hints:\n\n* Check for lockfiles: `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`.\n* Check CI scripts for `npm install` vs `npm ci`.\n* Search for `postinstall` scripts and suspicious build steps.\n\nFix:\n\n* Use lockfile and enforce it in CI (e.g., `npm ci`).\n* Run audits regularly; pin/upgrade responsibly.\n* Consider restricting install scripts where feasible.\n\nNotes:\n\n* npm docs describe `npm audit` as submitting the project dependency tree to the registry to receive a report of known vulnerabilities and (optionally) applying remediations via `npm audit fix`, while noting some vulns require manual review. ([npm Docs][20])\n* npm docs describe `npm ci` as intended for automated/CI environments, requiring an existing lockfile and failing if `package.json` and lockfile do not match. ([npm Docs][21])\n* OWASP NPM security guidance recommends enforcing the lockfile and explicitly calls out `npm ci` / `yarn install --frozen-lockfile` to abort on inconsistencies, and highlights the risk of install-time scripts and the option to use `--ignore-scripts` to reduce attack surface. ([OWASP Cheat Sheet Series][22])\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* Raw HTML / XSS escape hatches:\n\n  * `dangerouslySetInnerHTML`, `__html:`\n  * Markdown HTML passthrough flags: `rehype-raw`, `allowDangerousHtml`, `sanitize: false`\n* DOM XSS sinks:\n\n  * `innerHTML`, `outerHTML`, `insertAdjacentHTML`, `document.write`, `DOMParser`, `createContextualFragment`\n* Dangerous JS execution:\n\n  * `eval(`, `new Function(`, `setTimeout(\"`, `setInterval(\"`\n* Untrusted URL injection / navigation:\n\n  * `href={` / `src={` with untrusted values\n  * `window.location`, `location.href`, `window.open`, `navigate(`\n  * Query params: `next`, `returnTo`, `redirect`\n* Token/session risk:\n\n  * `localStorage.setItem`, `sessionStorage.setItem`, `getItem(` with `token`, `jwt`, `refresh`\n* Cookie/CSRF coupling:\n\n  * `credentials: 'include'`, `withCredentials: true` on state-changing requests without CSRF headers\n* Third-party scripts:\n\n  * `<script src=...>` in `public/index.html`\n  * Tag manager snippets and dynamic script insertion\n* Service workers:\n\n  * `navigator.serviceWorker.register`, Workbox usage, custom `fetch` handlers\n* postMessage:\n\n  * `postMessage(` with `*`, missing `event.origin` checks\n* Supply chain:\n\n  * Missing lockfile, CI uses `npm install`, no audit step, risky postinstall scripts\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (React escape hatch vs DOM sink vs navigation vs storage)\n* protective controls present (sanitization, allowlists, CSP/Trusted Types, CSRF tokens, headers, governance)\n\n---\n\n## 6) Sources (accessed 2026-01-26)\n\nPrimary React documentation:\n\n* React 19 stable announcement — `https://react.dev/blog/2024/12/05/react-19` ([React][23])\n* React DOM docs: `dangerouslySetInnerHTML` warning — `https://react.dev/reference/react-dom/components/common#dangerouslysetting-the-inner-html` ([React][12])\n* React (legacy) JSX escaping statement — `https://legacy.reactjs.org/docs/introducing-jsx.html` ([React][14])\n\nOWASP Cheat Sheet Series:\n\n* Cross Site Scripting Prevention (framework escape hatches; React `dangerouslySetInnerHTML`; URL validation notes) — `https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][9])\n* Content Security Policy — `https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][2])\n* Cross-Site Request Forgery Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][6])\n* HTML5 Security (Web Storage, postMessage, tabnabbing, sandboxed frames) — `https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][4])\n* Third Party JavaScript Management — `https://cheatsheetseries.owasp.org/cheatsheets/Third_Party_Javascript_Management_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][5])\n* File Upload — `https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][19])\n* NPM Security best practices — `https://cheatsheetseries.owasp.org/cheatsheets/NPM_Security_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][22])\n\nBrowser / platform references (MDN, W3C):\n\n* Trusted Types API — `https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API` ([MDN Web Docs][3])\n* W3C Trusted Types spec — `https://www.w3.org/TR/trusted-types/` ([W3C][15])\n* Subresource Integrity — `https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity` ([MDN Web Docs][7])\n* Clickjacking defenses overview — `https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/Clickjacking` ([MDN Web Docs][8])\n* Using Service Workers (HTTPS requirement; proxy-like behavior) — `https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers` ([MDN Web Docs][10])\n* Secure contexts (powerful APIs restricted to HTTPS) — `https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Secure_Contexts` ([MDN Web Docs][18])\n* Link `rel` values (noopener/noreferrer) — `https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel` ([MDN Web Docs][17])\n\nBuild tooling / env exposure references:\n\n* Create React App env variables warning — `https://create-react-app.dev/docs/adding-custom-environment-variables/` ([create-react-app.dev][1])\n* Vite env variables security notes — `https://vite.dev/guide/env-and-mode` ([vitejs][11])\n\nAuth/token storage guidance:\n\n* OAuth 2.0 for Browser-Based Apps (token storage discussion) — `https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps` ([IETF Datatracker][16])\n\nDependency tooling references:\n\n* npm audit docs — `https://docs.npmjs.com/cli/v10/commands/npm-audit/` ([npm Docs][20])\n* npm ci docs — `https://docs.npmjs.com/cli/v10/commands/npm-ci/` ([npm Docs][21])\n\nSanitizer reference:\n\n* DOMPurify — `https://github.com/cure53/DOMPurify` ([GitHub][13])\n\n[1]: https://create-react-app.dev/docs/adding-custom-environment-variables/ \"Adding Custom Environment Variables | Create React App\"\n[2]: https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html \"Content Security Policy - OWASP Cheat Sheet Series\"\n[3]: https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API \"Trusted Types API - Web APIs | MDN\"\n[4]: https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html \"HTML5 Security - OWASP Cheat Sheet Series\"\n[5]: https://cheatsheetseries.owasp.org/cheatsheets/Third_Party_Javascript_Management_Cheat_Sheet.html \"Third Party Javascript Management - OWASP Cheat Sheet Series\"\n[6]: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html \"Cross-Site Request Forgery Prevention - OWASP Cheat Sheet Series\"\n[7]: https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity \"Subresource Integrity - Security | MDN\"\n[8]: https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/Clickjacking \"Clickjacking - Security | MDN\"\n[9]: https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html \"Cross Site Scripting Prevention - OWASP Cheat Sheet Series\"\n[10]: https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers \"Using Service Workers - Web APIs | MDN\"\n[11]: https://vite.dev/guide/env-and-mode \"Env Variables and Modes | Vite\"\n[12]: https://react.dev/reference/react-dom/components/common \"Common components (e.g. <div>) – React\"\n[13]: https://github.com/cure53/DOMPurify \"GitHub - cure53/DOMPurify: DOMPurify - a DOM-only, super-fast, uber-tolerant XSS sanitizer for HTML, MathML and SVG. DOMPurify works with a secure default, but offers a lot of configurability and hooks. Demo:\"\n[14]: https://legacy.reactjs.org/docs/introducing-jsx.html \"Introducing JSX – React\"\n[15]: https://www.w3.org/TR/trusted-types/ \"Trusted Types\"\n[16]: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps \"\n\n                draft-ietf-oauth-browser-based-apps-26\n\n        \"\n[17]: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel \"HTML attribute: rel - HTML | MDN\"\n[18]: https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Secure_Contexts \"Secure contexts - Security | MDN\"\n[19]: https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html \"File Upload - OWASP Cheat Sheet Series\"\n[20]: https://docs.npmjs.com/cli/v10/commands/npm-audit \"npm-audit | npm Docs\"\n[21]: https://docs.npmjs.com/cli/v10/commands/npm-ci \"npm-ci | npm Docs\"\n[22]: https://cheatsheetseries.owasp.org/cheatsheets/NPM_Security_Cheat_Sheet.html \"NPM Security - OWASP Cheat Sheet Series\"\n[23]: https://react.dev/blog/2024/12/05/react-19 \"React v19 – React\"\n","core/skills/builtin/security-best-practices/references/javascript-typescript-vue-web-frontend-security.md":"# Vue.js Web Security Spec (Vue 3.x, TypeScript/JavaScript, common tooling: Vite)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new Vue code.\n2. **Security review / vulnerability hunting** in existing Vue code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session cookies, auth tokens).\n* MUST NOT “fix” security by disabling protections (e.g., weakening CSP, turning on unsafe template compilation, using `v-html` as a shortcut, bypassing backend auth, or “just store the token in localStorage”).\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and configuration values that justify the claim.\n* MUST treat uncertainty honestly: if a protection might exist at the edge (CDN, reverse proxy, WAF, server headers), report it as “not visible in repo; verify runtime/infra config”.\n* MUST remember the frontend trust model: **any code shipped to browsers is attacker-readable and attacker-modifiable**. Secrets and “security enforcement” cannot rely on frontend-only logic.\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new Vue code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default framework features and proven libraries over custom security code.\n* MUST avoid introducing new risky sinks (runtime template compilation, `v-html` / `innerHTML`, unsafe URL navigation, dynamic script injection, etc.). ([Vue.js][1])\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a Vue repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. Build/deploy entrypoints and hosting config (Docker, CI, static hosting, SSR server).\n2. Secrets exposure (env usage, `.env*`, hard-coded keys). ([vitejs][2])\n3. XSS surface: templates, `v-html` / `innerHTML`, URL/style injection, DOM APIs. ([Vue.js][1])\n4. Auth/session handling in the browser (token storage, credentialed requests, CSRF integration). ([Vue.js][1])\n5. Routing/navigation (open redirects, “return_to/next”, unsafe external navigation). ([Vue.js][1])\n6. Third-party scripts and content (CDN assets, analytics, widgets, iframes). ([Vue.js][1])\n7. Security headers and browser hardening expectations (CSP, clickjacking). ([Vue.js][1])\n8. SSR-specific concerns (state serialization, template boundaries) when applicable. ([Vue.js][1])\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nIn a Vue app, untrusted input includes (non-exhaustive):\n\n* Anything from APIs: `fetch`, `axios`, GraphQL responses, webhooks, third-party SDKs.\n* Router-controlled data: `route.params`, `route.query`, `route.hash`, and anything derived from `window.location`.\n* User-controlled persisted content: DB-backed content displayed in the UI (comments, profiles, CMS content).\n* Browser-controlled storage: `localStorage`, `sessionStorage`, `IndexedDB`.\n* Cross-window messages: `postMessage` inputs.\n* Anything that can be influenced by an attacker through DOM clobbering or injected HTML (especially if Vue is mounted onto non-sterile DOM). ([Vue.js][1])\n\n### 2.2 State-changing action (frontend perspective)\n\nAn action is state-changing if it can:\n\n* Create/update/delete data via API calls.\n* Change authentication/session state (login, logout, refresh token).\n* Trigger privileged operations (payments, admin actions).\n* Cause side effects (sending emails, triggering webhooks, changing account settings).\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + component/function + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common Vue/front-end misconfigurations.\n\n* MUST ship a **production build** (not a development build or dev server). ([Vue.js][3])\n* MUST NOT ship secrets in frontend bundles; treat all client-exposed env variables as public. ([vitejs][2])\n* MUST NOT render non-trusted templates or allow user-provided Vue templates (equivalent to arbitrary JS execution). ([Vue.js][1])\n* SHOULD avoid raw HTML injection (`v-html`, `innerHTML`) unless content is trusted or strongly sandboxed. ([Vue.js][1])\n* SHOULD deploy baseline security headers (especially CSP and clickjacking defenses) at the server/CDN layer. ([OWASP Cheat Sheet Series][4])\n* SHOULD use safe auth patterns (prefer HttpOnly cookies for session tokens; coordinate with backend on CSRF). ([Vue.js][1])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### VUE-DEPLOY-001: Do not run dev/preview servers in production\n\nSeverity: High\n\nRequired:\n\n* MUST NOT deploy the Vite/Vue dev server (`vite`, `npm run dev`, HMR) as the production server.\n* MUST NOT use `vite preview` as a production server. ([vitejs][5])\n* MUST build (`vite build`) and serve the built assets using a production-grade static server/CDN, or a production SSR server if you are doing SSR. ([vitejs][6])\n\nInsecure patterns:\n\n* Docker/Procfile/systemd running `vite`, `npm run dev`, or `vite preview` as the production entrypoint.\n* Publicly exposed HMR endpoints.\n\nDetection hints:\n\n* Search: `vite`, `npm run dev`, `pnpm dev`, `yarn dev`, `vite preview`, `vue-cli-service serve`.\n* Check Docker `CMD`, `ENTRYPOINT`, CI deploy scripts, platform config.\n\nFix:\n\n* Build artifacts with `vite build`.\n* Serve `dist/` with hardened hosting (CDN/static server) or integrate into your backend server as static assets.\n\nNotes:\n\n* Using dev/preview servers locally is fine; only flag if it is the production entrypoint.\n\n---\n\n### VUE-DEPLOY-002: Use Vue production builds and keep devtools off in production\n\nSeverity: Medium (High if production devtools/debug hooks are enabled)\n\nRequired:\n\n* If loading Vue from CDN/self-host without a bundler, MUST use the `.prod.js` builds in production. ([Vue.js][3])\n* SHOULD ensure production bundles do not enable Vue devtools in production builds, and SHOULD not intentionally enable production devtools flags. ([Vue.js][7])\n\nInsecure patterns:\n\n* Production includes development build artifacts.\n* Explicitly enabling production devtools/diagnostic hooks.\n\nDetection hints:\n\n* Search HTML for `vue.global.js` / non-`.prod.js` variants when using CDN builds.\n* Search build config for Vue feature flags like `__VUE_PROD_DEVTOOLS__`. ([Vue.js][7])\n\nFix:\n\n* Switch to production build artifacts and ensure compile-time flags are configured for production.\n\n---\n\n### VUE-SECRETS-001: Never ship secrets in frontend code or env variables\n\nSeverity: High (Critical if real credentials are exposed)\n\nRequired:\n\n* MUST treat all frontend code and configuration as public.\n* MUST NOT embed secrets in:\n\n  * source code\n  * `.env` files committed to repo\n  * `import.meta.env.*` variables included in the bundle\n* MUST assume any env var that ends up in the client bundle is attacker-readable. ([vitejs][2])\n\nInsecure patterns:\n\n* `VITE_API_KEY=...` containing a true secret (not just a public identifier).\n* Hard-coded API keys, private tokens, service credentials, signing keys in JS/TS.\n\nDetection hints:\n\n* Search: `VITE_`, `import.meta.env`, `.env`, `.env.production`, `.env.*.local`.\n* Grep for `API_KEY`, `SECRET`, `TOKEN`, `PRIVATE_KEY`, `BEGIN`, `sk-`, `AKIA`, etc.\n\nFix:\n\n* Move secrets to backend/edge functions.\n* Use backend-minted short-lived tokens for the browser when needed.\n\nNotes:\n\n* Vite specifically warns that `.env.*.local` should be gitignored and that `VITE_*` vars end up in the client bundle, so they must not contain sensitive info. ([vitejs][2])\n\n---\n\n### VUE-SECRETS-002: Do not broaden Vite env exposure\n\nSeverity: High\n\nRequired:\n\n* MUST NOT configure Vite to expose all environment variables to the client.\n* SHOULD keep `envPrefix` strict and explicit.\n\nInsecure patterns:\n\n* Setting `envPrefix` to overly broad values (or `''`) to “make env vars work”.\n* Custom scripts that inject server secrets into global variables in HTML at build time.\n\nDetection hints:\n\n* Check `vite.config.*` for `envPrefix`.\n* Look for `define: { 'process.env': ... }` or manual injection into `window.__CONFIG__`.\n\nFix:\n\n* Keep secrets server-side.\n* Only expose non-sensitive values intentionally designed to be public.\n\nNotes:\n\n* Vite’s docs explain that only prefixed variables are exposed and that exposed variables land in the client bundle. ([vitejs][2])\n\n---\n\n### VUE-XSS-001: Prefer Vue’s default escaping; avoid raw HTML injection\n\nSeverity: High\n\nRequired:\n\n* MUST rely on Vue’s automatic escaping for text interpolation and attribute binding where possible. ([Vue.js][1])\n* MUST NOT render user-provided HTML via:\n\n  * `v-html`\n  * `innerHTML` in render functions / JSX\n  * direct DOM APIs (`element.innerHTML`, `insertAdjacentHTML`)\n    unless the HTML is trusted or robustly sanitized and the risk is explicitly accepted. ([Vue.js][1])\n\nInsecure patterns:\n\n* `<div v-html=\"userProvidedHtml\"></div>`\n* `h('div', { innerHTML: userProvidedHtml })`\n* `<div innerHTML={userProvidedHtml}></div>`\n* `el.innerHTML = untrusted`\n\nDetection hints:\n\n* Search: `v-html`, `innerHTML`, `insertAdjacentHTML`, `DOMParser`, `document.write`.\n\nFix:\n\n* Render untrusted content as text (interpolation).\n* If HTML rendering is required (e.g., Markdown), sanitize with a well-maintained HTML sanitizer and apply defense-in-depth (CSP, Trusted Types). ([Vue.js][1])\n\nNotes:\n\n* Vue’s docs explicitly warn that user-provided HTML is never “100% safe” unless sandboxed or strictly self-only exposure. ([Vue.js][1])\n\n---\n\n### VUE-XSS-002: Never use non-trusted templates (client-side template/code injection)\n\nSeverity: Critical\n\nRequired:\n\n* MUST NOT use non-trusted content as a Vue component template.\n* MUST treat “user can write a Vue template” as “user can execute arbitrary JavaScript in your app”, and potentially in SSR contexts too. ([Vue.js][1])\n* SHOULD prefer the runtime-only build (templates compiled at build time) and avoid shipping the runtime compiler unless you have a vetted need.\n\nInsecure patterns:\n\n* `createApp({ template: '<div>' + userProvidedString + '</div>' }).mount(...)`\n* Storing templates in DB and compiling/rendering them in the browser.\n* Admin/CMS features that allow entering Vue template syntax.\n\nDetection hints:\n\n* Search: `template:` where the value is not a static string.\n* Search: `@vue/compiler-dom`, `compile(`, “runtime compiler” build selection, dynamic SFC compilation.\n* Search for “template editor”, “custom template”, “theme HTML” features.\n\nFix:\n\n* Treat templates as code: keep them developer-controlled.\n* If end-user customization is required, use a safe format (restricted Markdown subset) rendered via a sanitizer, or isolate in a sandboxed iframe.\n\n---\n\n### VUE-XSS-003: Do not mount Vue onto DOM that may contain user-provided server-rendered HTML\n\nSeverity: Medium\n\nRequired:\n\n* MUST NOT mount Vue on nodes that may contain server-rendered and user-provided content (because attacker-controlled HTML that is “safe as HTML” may become unsafe as a Vue template). ([Vue.js][1])\n* SHOULD mount Vue into a “sterile” root element and render the app’s DOM from Vue-controlled templates/components.\n\nInsecure patterns:\n\n* Server renders user content into `#app`, then Vue mounts on `#app` and compiles/interprets that DOM as a template.\n* “Sprinkling Vue” on large server-rendered pages that include user-generated content.\n\nDetection hints:\n\n* Check server templates (e.g., Rails/Django/Express templates) for user HTML inserted inside the Vue mount root.\n* Look for `mount('#app')` where `#app` includes server-rendered UGC.\n\nFix:\n\n* Move user-rendered HTML outside the Vue mount root, or render it in a safe way (text/sanitized HTML) from Vue components.\n\n---\n\n### VUE-XSS-004: Prevent URL injection in bindings and navigations\n\nSeverity: High\n\nRequired:\n\n* MUST validate/sanitize any user-influenced URL before binding to navigation sinks (`href`, `src`, `action`, `window.location`, `window.open`, router navigation to external).\n* MUST specifically prevent `javascript:` URL execution in bindings like `<a :href=\"userProvidedUrl\">`. ([Vue.js][1])\n* SHOULD validate protocol and destination (allowlist `https:` and expected hosts; allow `mailto:`/`tel:` only if intended).\n\nInsecure patterns:\n\n* `<iframe :src=\"userProvidedUrl\">`\n* `window.location = route.query.next`\n* `window.open(userProvidedUrl)`\n\nDetection hints:\n\n* Search: `:href=`, `:src=`, `window.location`, `location.href`, `window.open`, `router.push(` with untrusted input.\n* Look for `next`, `return_to`, `redirect` query params.\n\nFix:\n\n* Prefer internal navigation via route names/paths you control.\n* For external URLs: parse with `new URL(...)`, allowlist protocol/host, reject `javascript:` and other dangerous schemes.\n* Sanitize and validate on the backend before storing user URLs (Vue docs explicitly recommend backend sanitization). ([Vue.js][1])\n\n---\n\n### VUE-XSS-005: Prevent style/CSS injection and UI redress\n\nSeverity: Low\n\nRequired:\n\n* MUST NOT bind attacker-controlled CSS strings broadly (e.g., `:style=\"userProvidedStyles\"`).\n* SHOULD use Vue’s style object syntax and only allow safe, specific properties if user customization is needed. ([Vue.js][1])\n* SHOULD isolate “user can control layout/CSS” features inside sandboxed iframes.\n\nInsecure patterns:\n\n* `:style=\"userProvidedStyles\"` where styles are attacker-controlled.\n* Rendering user-provided `<style>` content (even if Vue blocks some patterns, don’t try to work around it).\n\nDetection hints:\n\n* Search: `:style=\"` bound to non-constant variables that originate from API/user content.\n* Search for “custom CSS”, “theme editor”, “profile CSS”.\n\nFix:\n\n* Allowlist properties and values; avoid raw style strings.\n* Use sandboxed iframes for rich user customization.\n\n---\n\n### VUE-XSS-006: Never bind user-provided JavaScript into event handler attributes\n\nSeverity: Critical\n\nRequired:\n\n* MUST NOT bind attacker-provided strings into event handler attributes (e.g., `onclick`, `onfocus`, etc.).\n* MUST treat “user-provided JS” as unsafe unless sandboxed and self-only exposure is guaranteed. ([Vue.js][1])\n\nInsecure patterns:\n\n* `<div :onclick=\"userProvidedString\">`\n* `<a :onmouseenter=\"userProvidedString\">`\n\nDetection hints:\n\n* Search: `:on` followed by event attribute names (`:onclick`, `:onload`, etc.).\n* Search for `setAttribute('on` patterns.\n\nFix:\n\n* Use real event listeners with developer-controlled handlers.\n* If you truly need user scripting, isolate it (sandboxed iframe + strict boundaries).\n\n---\n\n### VUE-ROUTER-001: Do not treat client-side route guards as authorization\n\nSeverity: High\n\nRequired:\n\n* MUST NOT rely on Vue Router guards, UI hiding, or client-side checks to enforce authorization.\n* MUST enforce authorization on the backend for every privileged action and sensitive data response. ([OWASP Cheat Sheet Series][8])\n\nInsecure patterns:\n\n* “Admin route is protected because `beforeEach` checks `user.isAdmin`.”\n* Sensitive API endpoints that assume “the frontend won’t call this unless allowed.”\n\nDetection hints:\n\n* Search `router.beforeEach` for role-based gating and see if the backend is also enforcing.\n* Look for “security by route meta” patterns (`meta.requiresAdmin`) with no server corroboration.\n\nFix:\n\n* Keep route guards as UX only (reduce accidental access), but enforce real checks server-side.\n\n---\n\n### VUE-ROUTER-002: Prevent open redirects and unsafe “return_to/next” handling\n\nSeverity: Low\n\nRequired:\n\n* MUST validate redirect destinations derived from untrusted input (`next`, `return_to`, `redirect`).\n* SHOULD allow only same-site relative paths or an explicit allowlist of destinations.\n* MUST NOT allow non `http` / `https` protos (such as `javascript:`)\n\nInsecure patterns:\n\n* `router.push(route.query.next as string)`\n* `window.location.href = route.query.redirect`\n\nDetection hints:\n\n* Search for `route.query.next`, `route.query.redirect`, `return_to`, `continue`, `callback`.\n* Trace the value into router/window navigation sinks.\n\nFix:\n\n* Allow only relative paths starting with `/` (and reject `//host`, `javascript:`, etc.).\n* Prefer redirecting to named routes you control.\n\nNotes:\n\n* Even Vue’s docs note that sanitized URLs still may not guarantee safe destinations. ([Vue.js][1])\n\n---\n\n### VUE-AUTH-001: Token storage must assume XSS is possible\n\nSeverity: Low\n\nRequired:\n\n* MUST assume any token accessible to JavaScript can be stolen via XSS.\n* SHOULD prefer HttpOnly cookies (set by the backend) for session tokens, combined with CSRF protections where relevant. ([Vue.js][1])\n* SHOULD avoid storing long-lived tokens (especially refresh tokens) in `localStorage`/`sessionStorage`.\n\nInsecure patterns:\n\n* `localStorage.setItem('token', ...)` for long-lived bearer tokens.\n* Storing refresh tokens in JS-accessible storage.\n\nDetection hints:\n\n* Search: `localStorage`, `sessionStorage`, `indexedDB`, `persist`, `pinia-plugin-persistedstate`.\n* Identify whether stored values are auth/session material.\n\nFix:\n\n* Prefer backend-managed sessions via HttpOnly cookies.\n* If bearer tokens are unavoidable, keep them short-lived, stored in memory, and rotate frequently; combine with strong XSS mitigations (CSP, Trusted Types, strict sanitization). ([OWASP Cheat Sheet Series][4])\n\n---\n\n### VUE-CSRF-001: Coordinate with the backend for CSRF when using cookies\n\nSeverity: High (for cookie-authenticated state-changing requests)\n\nNOTE: If the application is not using cookie based authentication (for example if it passes an Authorization header), then CSRF is not a concern\n\nRequired:\n\n* If API requests include cookies (`credentials: 'include'` / `withCredentials: true`) and cookies authenticate the user, MUST include CSRF protections coordinated with the backend (token/header patterns, Origin checks, SameSite cookies as defense-in-depth). ([Vue.js][1])\n* MUST NOT “solve CORS/CSRF errors” by disabling protections on the backend or using `mode: 'no-cors'` on the frontend.\n\nInsecure patterns:\n\n* `fetch(url, { credentials: 'include', method: 'POST', body: ... })` with no CSRF token/header usage anywhere.\n* Enabling cross-origin credentialed requests without strict origin allowlists (backend-side).\n\nDetection hints:\n\n* Search: `credentials: 'include'`, `withCredentials`, `xsrf`, `csrf`, `X-CSRF-Token`, `X-XSRF-TOKEN`.\n* Look at API wrapper modules for headers and cookie settings.\n\nFix:\n\n* Implement backend-issued CSRF tokens and require them on state-changing requests.\n* Keep cookies `SameSite=Lax/Strict` where compatible and verify Origin/Referer where appropriate (backend-driven). ([OWASP Cheat Sheet Series][9])\n\nNotes:\n\n* Vue’s docs explicitly say CSRF is primarily backend-addressed but recommends coordinating on CSRF token submission. ([Vue.js][1])\n\n---\n\n### VUE-HTTP-001: Do not put secrets in URLs; avoid leaking sensitive data in navigation/logs\n\nSeverity: Medium\n\nRequired:\n\n* MUST NOT place tokens/secrets in query strings or fragments (they leak via logs, referrers, browser history).\n* SHOULD avoid logging sensitive values to console in production.\n\nInsecure patterns:\n\n* `/?token=...`, `/#access_token=...` used beyond short-lived OAuth handoff.\n* `console.log(userSession)` that includes tokens/PII.\n\nDetection hints:\n\n* Search for `token=` in router parsing, auth callback handlers, and analytics logs.\n* Search for `console.log(` around auth code.\n\nFix:\n\n* Use Authorization headers or HttpOnly cookies.\n* Scrub logs; gate debug logs behind dev-only checks.\n\n---\n\n### VUE-HEADERS-001: Require security headers at the deployment layer\n\nSeverity: Medium\n\nRequired:\n\n* SHOULD deploy a CSP (`Content-Security-Policy`) suitable for your Vue app.\n* SHOULD deploy clickjacking defenses (CSP `frame-ancestors` and/or `X-Frame-Options`) unless intentional embedding is required.\n* SHOULD deploy `X-Content-Type-Options: nosniff`, plus other headers as appropriate (Referrer-Policy, Permissions-Policy). ([OWASP Cheat Sheet Series][4])\n\nInsecure patterns:\n\n* No evidence of headers in server/CDN config for an app with UGC or rich HTML rendering.\n* CSP includes `unsafe-inline`/`unsafe-eval` without strong justification.\n\nDetection hints:\n\n* Look for hosting config: nginx, Netlify/Vercel headers config, CloudFront/Cloudflare rules.\n* If absent in repo, flag as “verify at edge”.\n\nFix:\n\n* Set headers at the edge or in the server. Start with a conservative CSP and tighten.\n\n---\n\n### VUE-CSP-001: Use Trusted Types and DOM XSS hardening when feasible\n\nSeverity: Low\n\nRequired:\n\n* For apps with significant DOM injection surface (rich text, plugins, `v-html`), SHOULD consider enabling Trusted Types to reduce DOM XSS risk. ([web.dev][10])\n* SHOULD treat Trusted Types as defense-in-depth, not a replacement for sanitization.\n\nInsecure patterns:\n\n* Frequent use of `innerHTML`/`v-html` without sanitization or CSP hardening.\n\nDetection hints:\n\n* Search: `v-html`, `innerHTML`, `insertAdjacentHTML`.\n* Check CSP for `require-trusted-types-for 'script'` usage (if headers are in repo).\n\nFix:\n\n* Reduce/centralize HTML injection, sanitize inputs, and add Trusted Types policies where appropriate.\n\n---\n\n### VUE-THIRDPARTY-001: Avoid dynamic third-party script injection; prefer static, vetted loading\n\nSeverity: Low\n\nRequired:\n\n* MUST NOT inject `<script src=\"...\">` where the URL is user-controlled.\n* SHOULD treat third-party widgets/analytics as supply-chain risk; load only from vetted, pinned sources.\n\nInsecure patterns:\n\n* `const s=document.createElement('script'); s.src = userProvidedUrl; ...`\n* “Plugin marketplace” that loads arbitrary remote scripts.\n\nDetection hints:\n\n* Search: `createElement('script')`, `.src =`, `appendChild(script)`.\n* Search for “loadExternalScript”, “injectScript”, “cdnUrl”.\n\nFix:\n\n* Bundle dependencies, or allowlist strict origins and enforce integrity (see SRI rule).\n* Consider sandboxed iframes for untrusted third-party UI.\n\n---\n\n### VUE-SRI-001: Use Subresource Integrity for CDN-hosted scripts/styles\n\nSeverity: Low\n\nRequired:\n\n* If loading scripts/styles from a CDN, SHOULD use Subresource Integrity (`integrity` attribute) with appropriate `crossorigin` configuration. ([MDN Web Docs][11])\n* SHOULD prefer self-hosting or bundling over runtime CDN dependencies for security-critical code.\n\nInsecure patterns:\n\n* `<script src=\"https://cdn.example/...\">` with no `integrity`.\n* Remote script URLs that can change content without version pinning.\n\nDetection hints:\n\n* Search `index.html` and server templates for `https://` script/style tags.\n* Check for `integrity=`.\n\nFix:\n\n* Add SRI hashes (and pin versions), or bundle assets with your build.\n\n---\n\n### VUE-SUPPLY-001: Dependency and patch hygiene is mandatory\n\nSeverity: Low\n\nRequired:\n\n* SHOULD keep Vue and official companion libraries updated; Vue explicitly recommends using latest versions to remain as secure as possible. ([Vue.js][1])\n* MUST respond to security advisories promptly.\n* SHOULD pin dependencies and keep lockfiles committed (to reduce drift in production artifacts).\n\nInsecure patterns:\n\n* Outdated major versions with known CVEs.\n* No lockfile in repo; wide semver ranges for critical deps.\n* Ignoring advisories for template/rendering/compiler packages.\n\nDetection hints:\n\n* Inspect `package.json`, lockfiles, CI install commands.\n* Search for `npm audit` disabled, “ignore vulnerabilities” scripts.\n\nFix:\n\n* Upgrade dependencies and add regression tests around the impacted behavior.\n* Add dependency scanning in CI.\n\n---\n\n### VUE-SSR-001: SSR adds additional trust boundaries; treat state injection as XSS-sensitive\n\nSeverity: Medium\n\nRequired:\n\n* When using SSR, MUST treat anything injected into the HTML document (initial state, serialized data, inline scripts) as XSS-sensitive.\n* MUST keep the “trusted templates only” rule even stricter, because unsafe templates can lead to server-side execution during rendering. ([Vue.js][1])\n* SHOULD follow Vue SSR documentation and best practices for SSR security. ([Vue.js][1])\n\nInsecure patterns:\n\n* Concatenating untrusted strings into SSR templates.\n* Injecting JSON into `<script>` blocks without robust escaping/serialization controls.\n\nDetection hints:\n\n* Search server code for `__INITIAL_STATE__`, `window.__*STATE__`, template concatenation, and SSR render pipelines.\n* Trace untrusted data into those sinks.\n\nFix:\n\n* Use safe serialization patterns recommended by your SSR stack.\n* Avoid rendering untrusted HTML; sanitize or isolate.\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* Dev/preview servers in production:\n\n  * `npm run dev`, `vite`, `vite preview`, `vue-cli-service serve` ([vitejs][5])\n* Secrets exposure:\n\n  * `.env`, `.env.production`, `.env.*.local`, `VITE_`, `import.meta.env`, hard-coded `API_KEY` / `SECRET` ([vitejs][2])\n* XSS sinks:\n\n  * `v-html`, `innerHTML`, `insertAdjacentHTML`, `DOMParser`, `document.write` ([Vue.js][1])\n* Client-side template injection:\n\n  * `template:` concatenation, `compile(`, runtime compiler usage, mounting on non-sterile DOM ([Vue.js][1])\n* URL injection / open redirects:\n\n  * `:href=\"...\"` / `:src=\"...\"` from user data\n  * `javascript:` occurrences\n  * `route.query.next` / `redirect` / `return_to` flowing into `router.push` or `window.location` ([Vue.js][1])\n* Style injection:\n\n  * `:style=\"userProvidedStyles\"` or user-driven theme CSS ([Vue.js][1])\n* Token storage:\n\n  * `localStorage.setItem('token'...)`, persisted auth stores, refresh tokens in JS-accessible storage\n* CSRF integration red flags:\n\n  * `credentials: 'include'` / `withCredentials: true` without any CSRF header/token handling ([Vue.js][1])\n* Third-party scripts:\n\n  * dynamic script injection (`createElement('script')`), CDN scripts without SRI ([MDN Web Docs][11])\n* External links security:\n\n  * `target=\"_blank\"` without `rel=\"noopener\"`/`noreferrer` (still recommended for legacy and explicitness) ([MDN Web Docs][12])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (HTML/DOM insertion, template compilation, URL navigation, style injection, script injection)\n* protective controls present (sanitization, allowlists, CSP/Trusted Types, backend validation)\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary Vue documentation:\n\n* Vue Docs: Security — `https://vuejs.org/guide/best-practices/security` ([Vue.js][1])\n* Vue Docs: Template Syntax (security warning about in-DOM templates) — `https://vuejs.org/guide/essentials/template-syntax` ([Vue.js][13])\n* Vue Docs: Production Deployment — `https://vuejs.org/guide/best-practices/production-deployment` ([Vue.js][3])\n* Vue Docs: Feature Flags — `https://link.vuejs.org/feature-flags` ([Vue.js][7])\n\nVite documentation (common Vue tooling):\n\n* Vite Docs: Env Variables and Modes (VITE_* exposure + security notes) — `https://vite.dev/guide/env-and-mode` ([vitejs][2])\n* Vite Docs: CLI (`vite preview` not designed for production) — `https://vite.dev/guide/cli` ([vitejs][5])\n* Vite Docs: Server Options (`server.host` can listen on public addresses) — `https://vite.dev/config/server-options` ([vitejs][14])\n\nOWASP and web platform hardening references:\n\n* OWASP Cheat Sheet Series: XSS Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html` ([Vue.js][1])\n* OWASP Cheat Sheet Series: CSRF Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][9])\n* OWASP Cheat Sheet Series: Authorization — `https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][8])\n* OWASP Cheat Sheet Series: HTTP Headers — `https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][4])\n* HTML5 Security Cheat Sheet (referenced by Vue) — `https://html5sec.org/` ([Vue.js][1])\n\nBrowser/platform references:\n\n* MDN: `rel=\"noopener\"` — `https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/noopener` ([MDN Web Docs][12])\n* MDN: Subresource Integrity — `https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity` ([MDN Web Docs][11])\n* web.dev: Trusted Types — `https://web.dev/trusted-types/` ([web.dev][10])\n\n[1]: https://vuejs.org/guide/best-practices/security \"https://vuejs.org/guide/best-practices/security\"\n[2]: https://vite.dev/guide/env-and-mode \"https://vite.dev/guide/env-and-mode\"\n[3]: https://vuejs.org/guide/best-practices/production-deployment \"https://vuejs.org/guide/best-practices/production-deployment\"\n[4]: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html\"\n[5]: https://vite.dev/guide/cli \"https://vite.dev/guide/cli\"\n[6]: https://vite.dev/guide/build \"https://vite.dev/guide/build\"\n[7]: https://vuejs.org/guide/best-practices/production-deployment?utm_source=chatgpt.com \"Production Deployment\"\n[8]: https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html\"\n[9]: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html\"\n[10]: https://web.dev/articles/trusted-types \"https://web.dev/articles/trusted-types\"\n[11]: https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity?utm_source=chatgpt.com \"Subresource Integrity - Security - MDN Web Docs\"\n[12]: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/noopener \"https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/noopener\"\n[13]: https://vuejs.org/guide/essentials/template-syntax \"Template Syntax | Vue.js\"\n[14]: https://vite.dev/config/server-options \"https://vite.dev/config/server-options\"\n","core/skills/builtin/security-best-practices/references/python-django-web-server-security.md":"# Django (Python) Web Security Spec (Django 6.0.x, Python 3.x)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new Django code.\n2. **Security review / vulnerability hunting** in existing Django code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session cookies, `SECRET_KEY`, `SECRET_KEY_FALLBACKS`, database passwords).\n* MUST NOT “fix” security by disabling protections (e.g., removing `CsrfViewMiddleware`, sprinkling `@csrf_exempt`, loosening `ALLOWED_HOSTS` to `['*']`, disabling `SecurityMiddleware`, disabling template auto-escaping, disabling permission checks).\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and concrete configuration values that justify the claim.\n* MUST treat uncertainty honestly: if a protection might exist in infrastructure (reverse proxy, WAF, CDN, ingress controller), report it as “not visible in app code; verify at runtime / edge config”.\n* MUST keep fixes compatible with Django’s intended security model: prefer Django’s built-ins (middleware, auth, forms, ORM) over custom security logic whenever possible. Django’s deployment checklist and system checks are part of the intended model. ([Django Project][1])\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new Django code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default Django APIs and proven libraries over custom security code.\n* MUST avoid introducing new risky sinks (dynamic template rendering from untrusted strings, unsafe redirects, unsafe file serving, shell execution, raw SQL string formatting, SSRF-capable URL fetchers from untrusted input).\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a Django repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. Deployment entrypoints (ASGI/WSGI), Dockerfiles, Procfiles, systemd units, platform manifests.\n2. `settings.py` and environment-specific settings modules.\n3. Middleware ordering and enabled protections.\n4. Authn/authz (login, session management, permissions, admin).\n5. CSRF protections and state-changing endpoints.\n6. Templates and XSS.\n7. File handling (uploads/downloads/static/media) and path traversal.\n8. Injection classes (SQL, command execution, unsafe deserialization).\n9. Outbound requests (SSRF).\n10. Redirect handling (open redirects) + CORS + security headers (CSP, HSTS, etc.).\n11. Dependency/pinning and patch posture.\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nExamples include:\n\n* `request.GET`, `request.POST`, `request.FILES`\n* `request.body`, JSON bodies (e.g., `json.loads(request.body)`), DRF `request.data`\n* URL path parameters (e.g., `<int:id>`, `<slug:...>`)\n* `request.headers` / `request.META` (including `HTTP_HOST`, `HTTP_ORIGIN`, `HTTP_REFERER`, `HTTP_X_FORWARDED_*`)\n* `request.COOKIES`\n* Any data from external systems (webhooks, third-party APIs, message queues)\n* Any persisted content that originated from users (DB rows, cached content, file uploads)\n\nDjango explicitly emphasizes “never trust user-controlled data” and recommends using forms/validation. ([Django Project][2])\n\n### 2.2 State-changing request\n\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook send), or initiate privileged actions.\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + function/class/view name + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common Django misconfigurations. Django provides a “Deployment checklist” and recommends running `manage.py check --deploy` against production settings. ([Django Project][1])\n\n### 3.1 Settings management pattern (SHOULD)\n\n* SHOULD use environment-based configuration (or a secret manager) so production settings are not hard-coded.\n* MUST treat sensitive settings as confidential (e.g., `SECRET_KEY`, DB passwords) and keep them out of source control. Django’s checklist explicitly recommends loading `SECRET_KEY` from env or a file rather than hardcoding. ([Django Project][1])\n* SHOULD separate dev vs prod settings modules, with safe defaults for production (fail closed if critical settings are missing). ([Django Project][1])\n\n### 3.2 Minimum baseline targets (production)\n\n* MUST NOT use `manage.py runserver` as the production entrypoint; use a production-ready WSGI or ASGI server. ([Django Project][1])\n* MUST set `DEBUG = False` in production. ([Django Project][1])\n* MUST set a strong, secret `SECRET_KEY` and keep it secret; MAY use `SECRET_KEY_FALLBACKS` for safe rotation. ([Django Project][1])\n* MUST set `ALLOWED_HOSTS` to expected hosts (no wildcard unless you do your own host validation). ([Django Project][1])\n* MUST enforce HTTPS for authenticated areas (ideally site-wide for any login-capable app) and set `CSRF_COOKIE_SECURE=True` and `SESSION_COOKIE_SECURE=True` when HTTPS is used. ([Django Project][1])\n* SHOULD enable key `SecurityMiddleware` headers/settings: HSTS, Referrer-Policy, COOP, nosniff, SSL redirect (with correct proxy configuration). ([Django Project][3])\n* MUST treat user uploads as untrusted; ensure your web server never interprets them as executable content; keep `MEDIA_ROOT` separate from `STATIC_ROOT`. ([Django Project][1])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### DJANGO-DEPLOY-001: Do not use Django’s development server in production\n\nSeverity: High (if production)\n\nRequired:\n\n* MUST NOT deploy `manage.py runserver` as the production server.\n* MUST run behind a production-grade WSGI or ASGI server. ([Django Project][1])\n\nInsecure patterns:\n\n* Production docs/scripts using `python manage.py runserver 0.0.0.0:8000`.\n* Docker `CMD`/entrypoint uses `runserver`.\n* Kubernetes/Procfile/systemd units invoking `runserver`.\n\nDetection hints:\n\n* Search for `manage.py runserver`, `runserver 0.0.0.0`, `--insecure`.\n* Check Docker `CMD/ENTRYPOINT`, Procfile, systemd unit files, Helm charts.\n\nFix:\n\n* Use a production server (WSGI/ASGI) as recommended in Django’s deployment checklist. ([Django Project][1])\n\nNote:\n\n* `runserver` is fine for local development. Only flag if it’s used as the production entrypoint.\n\n---\n\n### DJANGO-DEPLOY-002: `DEBUG` MUST be disabled in production\n\nSeverity: High\n\nRequired:\n\n* MUST set `DEBUG = False` in production.\n* MUST treat any mechanism that exposes debug pages/tracebacks to untrusted users as a critical information disclosure risk. Django’s checklist explicitly warns `DEBUG=True` leaks source excerpts, local variables, settings, and more. ([Django Project][1])\n\nInsecure patterns:\n\n* `DEBUG = True` in production settings.\n* Environment defaults to `DEBUG=True` unless explicitly overridden.\n\nDetection hints:\n\n* Search `DEBUG = True`, `DEBUG=os.environ.get(..., True)`, `DJANGO_DEBUG`, `.env` files.\n* Look for “production” settings modules that import from dev defaults.\n\nFix:\n\n* Set `DEBUG=False` in prod settings; use explicit environment config.\n* Ensure error reporting is via safe logging/monitoring, not debug pages. ([Django Project][1])\n\n---\n\n### DJANGO-CONFIG-001: `SECRET_KEY` must be strong, secret, and rotated safely\n\nSeverity: High (Critical if missing in production with signing/sessions)\n\nRequired:\n\n* MUST set a large random `SECRET_KEY` in production and keep it secret. ([Django Project][1])\n* MUST NOT commit it to source control or print/log it. ([Django Project][1])\n* SHOULD load it from env or a file/secret store (not hard-coded). ([Django Project][1])\n* MAY rotate keys using `SECRET_KEY_FALLBACKS` to avoid instantly invalidating all signed data; MUST remove old keys from fallbacks in a timely manner. ([Django Project][1])\n\nInsecure patterns:\n\n* Hard-coded `SECRET_KEY = \"...\"` in repo for production.\n* `SECRET_KEY` reused across environments.\n* `SECRET_KEY_FALLBACKS` contains long-expired keys indefinitely.\n\nDetection hints:\n\n* Search for `SECRET_KEY =`, `SECRET_KEY_FALLBACKS`, `.env` committed files, `print(settings.SECRET_KEY)`.\n\nFix:\n\n* Load from secret manager / environment variable.\n* If rotating:\n\n  * Set new `SECRET_KEY`\n  * Keep old key(s) temporarily in `SECRET_KEY_FALLBACKS`\n  * Remove old key(s) after the rotation window. ([Django Project][1])\n\n---\n\n### DJANGO-HOST-001: Host header must be validated (`ALLOWED_HOSTS` must be strict)\n\nSeverity: Medium\n\nRequired:\n\n* MUST set `ALLOWED_HOSTS` in production to your expected domains/hosts. ([Django Project][1])\n* MUST NOT set `ALLOWED_HOSTS = ['*']` in production unless you also implement your own robust `Host` validation (Django warns that wildcards require your own validation to avoid CSRF-class attacks). ([Django Project][1])\n* SHOULD configure the fronting web server to reject unknown hosts early (defense-in-depth). ([Django Project][1])\n\nInsecure patterns:\n\n* `ALLOWED_HOSTS = ['*']` (or env expands to `*`) in production.\n* `ALLOWED_HOSTS = []` with `DEBUG=False` (site won’t run, or misconfigured deployments attempt workarounds).\n\nDetection hints:\n\n* Search `ALLOWED_HOSTS`.\n* Check platform environment settings that override `ALLOWED_HOSTS`.\n\nFix:\n\n* Set `ALLOWED_HOSTS = ['example.com', 'www.example.com', ...]` for prod.\n* Keep dev hosts separate.\n\nNotes:\n\n* Django uses the Host header for URL construction; fake Host values can lead to CSRF, cache poisoning, and poisoned email links (Django security docs call this out). ([Django Project][2])\n\n---\n\n### DJANGO-HTTPS-001: If TLS is used cookie transport must be secured\n\nSeverity: High (Critical for auth-enabled apps)\n\nNOTE: Only enforce this if TLS is enabled, as it will break non-TLS applications\n\nIf using TLS:\n* MUST set:\n\n  * `CSRF_COOKIE_SECURE = True` ([Django Project][1])\n  * `SESSION_COOKIE_SECURE = True` ([Django Project][1])\n* SHOULD consider enabling:\n\n  * `SECURE_SSL_REDIRECT = True` (with correct proxy config) ([Django Project][3])\n  * HSTS via `SECURE_HSTS_SECONDS` (+ includeSubDomains/preload as appropriate). ([Django Project][3])\n\nInsecure patterns:\n\n* Login pages over HTTP, or mixed HTTP/HTTPS with the same session cookie.\n* `CSRF_COOKIE_SECURE=False` or `SESSION_COOKIE_SECURE=False` in production HTTPS.\n* HSTS enabled incorrectly (can break site for the duration).\n\nDetection hints:\n\n* Inspect `settings.py` for `CSRF_COOKIE_SECURE`, `SESSION_COOKIE_SECURE`, `SECURE_SSL_REDIRECT`, `SECURE_HSTS_SECONDS`.\n* Inspect proxy/ingress config for HTTP->HTTPS redirect behavior.\n\nFix:\n\n* Enable HTTPS redirect and secure cookies.\n* Add HSTS carefully (start with low value, validate, then increase). Django warns misconfig can break your site for the HSTS duration. ([Django Project][3])\n\n---\n\n### DJANGO-PROXY-001: Reverse proxy trust must be configured correctly (`SECURE_PROXY_SSL_HEADER`)\n\nSeverity: Medium (when behind a TLS proxy)\n\nRequired:\n\n* If behind a reverse proxy that terminates TLS, MUST configure Django so `request.is_secure()` reflects the *external* scheme, otherwise CSRF and other logic can break. Django documents using `SECURE_PROXY_SSL_HEADER` for this. ([Django Project][3])\n* MUST only set `SECURE_PROXY_SSL_HEADER` if you control the proxy (or have guarantees) and it strips inbound spoofed headers. Django explicitly warns misconfig can compromise security and lists required conditions. ([Django Project][3])\n\nInsecure patterns:\n\n* `SECURE_PROXY_SSL_HEADER = (\"HTTP_X_FORWARDED_PROTO\", \"https\")` in an environment where the proxy does not strip user-supplied `X-Forwarded-Proto`.\n* Infinite redirect loops after setting `SECURE_SSL_REDIRECT=True` (often indicates proxy HTTPS detection is wrong). ([Django Project][3])\n\nDetection hints:\n\n* Search `SECURE_PROXY_SSL_HEADER`, `SECURE_SSL_REDIRECT`.\n* Inspect ingress/proxy behavior for stripping forwarded headers.\n\nFix:\n\n* Set `SECURE_PROXY_SSL_HEADER` only if the proxy strips and sets the header correctly (per Django’s documented prerequisites). ([Django Project][3])\n\n---\n\n### DJANGO-SESS-001: Session cookies must use secure attributes in production\n\nSeverity: Medium (Only if TLS enabled)\n\nRequired (production, HTTPS):\n\n* MUST set `SESSION_COOKIE_SECURE=True` (only transmit over HTTPS). ([Django Project][3])\n* MUST keep `SESSION_COOKIE_HTTPONLY=True` (Django default is `True`). ([Django Project][3])\n* SHOULD keep `SESSION_COOKIE_SAMESITE='Lax'` (Django default is `Lax`) unless a justified cross-site flow requires `None`. ([Django Project][3])\n* SHOULD avoid setting `SESSION_COOKIE_DOMAIN` unless you truly need cross-subdomain cookies (subdomain-wide cookies expand attack surface).\n\nInsecure patterns:\n\n* `SESSION_COOKIE_SECURE=False` in production HTTPS.\n\nIMPORTANT NOTE: Only set `Secure` in production environment when TLS is configured. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n\n* `SESSION_COOKIE_HTTPONLY=False`.\n* `SESSION_COOKIE_SAMESITE=None` combined with cookie-authenticated state-changing endpoints (higher CSRF risk).\n\nDetection hints:\n\n* Search for `SESSION_COOKIE_` settings, `response.set_cookie(..., httponly=..., secure=..., samesite=...)`.\n\nFix:\n\n* Set the above explicitly in production settings.\n* Validate compatibility with your auth flows. ([Django Project][3])\n\n---\n\n### DJANGO-SESS-002: CSRF cookie settings must be deliberate (HttpOnly has tradeoffs)\n\nSeverity: Medium\n\nRequired:\n\n* SHOULD set `CSRF_COOKIE_SECURE=True` when using HTTPS/TLS. ([Django Project][3])\n* SHOULD keep `CSRF_COOKIE_SAMESITE='Lax'` unless you have a cross-site requirement. Django default is `Lax`. ([Django Project][3])\n* MAY set `CSRF_COOKIE_HTTPONLY=True` (default is `False`) if your frontend does not need to read the CSRF cookie. If you enable it, your JS must read the CSRF token from the DOM instead (Django documents this). ([Django Project][3])\n\nInsecure patterns:\n\n* `CSRF_COOKIE_SECURE=False` in production HTTPS/TLS.\n* Setting `CSRF_COOKIE_HTTPONLY=True` but still relying on “read csrftoken cookie in JS” patterns (breaks CSRF for AJAX).\n* `CSRF_COOKIE_SAMESITE=None` without a clear reason.\n\nDetection hints:\n\n* Search for `CSRF_COOKIE_` settings.\n* Search JS for `document.cookie` usage to fetch `csrftoken`.\n\nFix:\n\n* Align cookie settings with your CSRF token acquisition method (cookie vs DOM) as Django describes. ([Django Project][4])\n\n---\n\n### DJANGO-CSRF-001: Cookie-authenticated state-changing requests MUST be CSRF-protected\n\nSeverity: High\n\nRequired:\n\n* MUST keep `django.middleware.csrf.CsrfViewMiddleware` enabled (it is activated by default). ([Django Project][4])\n* MUST include `{% csrf_token %}` in internal POST forms; MUST NOT include it in forms that POST to external URLs (Django warns this leaks the token). ([Django Project][4])\n* MUST protect all state-changing endpoints (POST/PUT/PATCH/DELETE) that rely on cookies for authentication.\n* For AJAX/SPA calls, MUST send the CSRF token via the `X-CSRFToken` header (or configured header name) as documented. ([Django Project][4])\n* MUST be very careful with `@csrf_exempt` and use it only when absolutely necessary; if used, MUST replace CSRF with an appropriate alternative control (e.g., request signing for webhooks). Django explicitly warns about `csrf_exempt`. ([Django Project][2])\n\nInsecure patterns:\n\n* Missing `CsrfViewMiddleware` in `MIDDLEWARE`.\n* `@csrf_exempt` on general-purpose authenticated views.\n* POST/PUT/PATCH/DELETE endpoints with session auth and no CSRF tokens.\n* Using GET for state-changing actions (amplifies CSRF risk).\n\nDetection hints:\n\n* Inspect `settings.py` `MIDDLEWARE` for `CsrfViewMiddleware` and its order (Django notes it should come before middleware that assumes CSRF is handled). ([Django Project][4])\n* Search for `csrf_exempt`, `csrf_protect`, `ensure_csrf_cookie`.\n* Enumerate URL patterns for non-GET methods; confirm CSRF coverage.\n\nFix:\n\n* Re-enable `CsrfViewMiddleware`, add CSRF tokens to forms, and add AJAX header handling.\n* For caching decorators: if you cache a view that needs CSRF tokens, apply `@csrf_protect` as Django documents to avoid caching a response without CSRF cookie/Vary headers. ([Django Project][4])\n\nNotes:\n\n* When deployed with HTTPS, Django’s CSRF middleware also checks the Referer header for same-origin (Django security docs mention this). ([Django Project][2])\n\n---\n\n### DJANGO-XSS-001: Prevent reflected/stored XSS in templates and HTML generation\n\nSeverity: High\n\nRequired:\n\n* MUST rely on Django template auto-escaping (safe-by-default) for HTML templates. Django security docs highlight that Django templates escape dangerous characters but have limitations. ([Django Project][2])\n* MUST NOT disable auto-escaping broadly (`{% autoescape off %}`) unless the content is trusted or safely sanitized. ([Django Project][5])\n* MUST NOT mark untrusted content as safe:\n\n  * Avoid `mark_safe(...)` on user data.\n  * Avoid `|safe` on user-controlled content.\n* MUST be careful about HTML context pitfalls (e.g., unquoted attributes); Django explicitly shows an example where escaping does not protect an unquoted attribute context. ([Django Project][2])\n* SHOULD prefer safe HTML construction helpers (e.g., `format_html`) rather than manual concatenation that risks missing escapes. ([Django Project][6])\n\nInsecure patterns:\n\n* `{% autoescape off %}{{ user_input }}{% endautoescape %}`\n* `{{ user_input|safe }}`\n* `mark_safe(request.GET[\"q\"])`\n* Unquoted attribute injections: `<style class={{ var }}>...` (Django’s own example). ([Django Project][2])\n\nDetection hints:\n\n* Search templates for `|safe`, `autoescape off`, `safeseq`.\n* Search Python for `mark_safe`, `SafeString`, or direct HTML concatenation with request/DB values.\n* Review any code returning `HttpResponse(user_value)` where `user_value` contains HTML.\n\nFix:\n\n* Remove unsafe marking; sanitize only when strictly necessary (use an allowlist-based HTML sanitizer).\n* Quote attributes and avoid placing untrusted values into dangerous contexts.\n* Add CSP as defense-in-depth (see DJANGO-CSP-001). ([Django Project][2])\n\n---\n\n### DJANGO-TEMPLATE-001: Never render untrusted template source strings\n\nSeverity: High to Critical (depends on context and exposure)\n\nRequired:\n\n* MUST NOT render templates where the template source string is influenced by untrusted input (request, user content, DB rows editable by untrusted users).\n* MUST treat “template from string” patterns as dangerous, even if Django templates are more constrained than some other engines: they can still leak data from context, bypass escaping, and create XSS or content injection.\n\nInsecure patterns:\n\n* `Template(request.GET[\"tmpl\"]).render(Context(...))`\n* Saving user templates in the DB and rendering them with normal privileges/context.\n\nDetection hints:\n\n* Search for `django.template.Template(`, `Engine.from_string`, `.render(Context(` with non-constant strings.\n* Trace where the template string comes from (admin panels, DB, uploads, requests).\n\nFix:\n\n* Replace with non-executing formatting (e.g., `string.Template`, explicit placeholders) or a strict allowlisted rendering model.\n* If you *must* support user-defined templates, isolate heavily (separate service/tenant context, strict allowlists, and assume bypasses are possible).\n\n---\n\n### DJANGO-SQL-001: Prevent SQL injection (use ORM or parameterized raw SQL)\n\nSeverity: High\n\nRequired:\n\n* MUST use Django ORM/querysets for normal DB access; Django notes querysets are parameterized and protected from SQL injection under typical use. ([Django Project][2])\n* MUST be very careful with raw SQL; if using `raw()`, `cursor.execute()`, `extra()`, or `RawSQL`, MUST pass parameters separately (e.g., `params=`) and MUST NOT string-interpolate untrusted input into SQL. Django’s raw SQL docs warn to escape user-controlled parameters using `params`. ([Django Project][7])\n* MUST NOT quote placeholders in SQL templates (Django docs explicitly warn that quoting `%s` placeholders makes it unsafe). ([Django Project][8])\n* SHOULD avoid `extra()` and `RawSQL` unless necessary; Django security docs call for caution. ([Django Project][2])\n\nInsecure patterns:\n\n* `cursor.execute(f\"SELECT ... WHERE id={request.GET['id']}\")`\n* `Model.objects.raw(\"... %s\" % user_input)` (string formatting)\n* `extra(where=[f\"headline='{q}'\"])`\n* Quoted placeholders: `WHERE othercol = '%s'` (explicitly documented as unsafe). ([Django Project][8])\n\nDetection hints:\n\n* Grep for `.raw(`, `.extra(`, `RawSQL(`, `connection.cursor()`, `.execute(`.\n* Grep for SQL keywords (`SELECT`, `UPDATE`, `DELETE`, `INSERT`) in Python strings.\n* Track untrusted inputs into these call sites.\n\nFix:\n\n* Prefer ORM queries.\n* If raw SQL is unavoidable, use parameters (`params`, DB-API param binding) and do not quote placeholders. ([Django Project][7])\n\n---\n\n### DJANGO-CMD-001: Prevent OS command injection\n\nSeverity: Critical to High (depends on exposure)\n\nRequired:\n\n* MUST avoid executing system commands with attacker-influenced input.\n* If subprocess is necessary:\n\n  * MUST pass args as a list (not a shell string).\n  * MUST NOT use `shell=True` with attacker-influenced content.\n  * SHOULD use strict allowlists for variable components.\n* SHOULD prefer pure-Python libraries instead of shelling out.\n\nInsecure patterns:\n\n* `os.system(request.GET[\"cmd\"])`\n* `subprocess.run(f\"convert {path}\", shell=True)` where `path` is user-controlled.\n\nDetection hints:\n\n* Search `os.system`, `subprocess`, `Popen`, `shell=True`.\n* Trace request/DB inputs into those calls.\n\nFix:\n\n* Replace with library APIs; if unavoidable, hard-code executable and allowlist validated parameters.\n\n---\n\n### DJANGO-UPLOAD-001: File uploads must be validated, stored safely, and served safely\n\nSeverity: High\n\nRequired:\n\n* MUST treat all user uploads as untrusted. Django explicitly warns “Media files are uploaded by your users. They’re untrusted!” ([Django Project][1])\n* MUST ensure the web server never interprets user uploads as executable code (e.g., don’t allow uploaded `.php` or HTML to execute/inline as active content). ([Django Project][1])\n* MUST enforce size limits (at least at the web server; Django security docs recommend limiting upload size at the server to prevent DoS). ([Django Project][2])\n* SHOULD validate file types using allowlists and content checks (not only extensions).\n* SHOULD store uploads outside the application code directory and outside any static root.\n* SHOULD consider serving uploads from a separate top-level/second-level domain to reduce same-origin impact; Django security docs recommend a distinct domain and note that a subdomain may be insufficient for some protections. ([Django Project][2])\n* MUST be aware of polyglot upload risks: Django documents a case where HTML can be uploaded “as an image” by using a valid PNG header (and may be served as HTML depending on the web server). ([Django Project][2])\n\nInsecure patterns:\n\n* Serving uploads inline with `text/html` or without forcing download for potentially active formats.\n* Upload allowlist based only on extension.\n* Upload storage inside static roots or code roots.\n\nDetection hints:\n\n* Search for `request.FILES`, `FileField`, `ImageField`, upload forms/views.\n* Inspect upload serving paths and Nginx/Apache config (media handlers).\n* Check `MEDIA_URL`, `MEDIA_ROOT`, and static config.\n\nFix:\n\n* Configure the web server to serve uploads as inert bytes (no execution), and consider forcing `Content-Disposition: attachment` for risky types.\n* Use a separate domain for user content when warranted. ([Django Project][2])\n\n---\n\n### DJANGO-PATH-001: Prevent path traversal and unsafe file serving (static/media separation)\n\nSeverity: High\n\nRequired:\n\n* MUST NOT treat user input as a filesystem path for reads/writes/serving.\n* MUST keep `MEDIA_ROOT` and `STATIC_ROOT` distinct; Django settings docs explicitly warn they must have different values to avoid security implications. ([Django Project][3])\n* SHOULD prefer using Django storage APIs keyed by server-side identifiers rather than accepting arbitrary relative paths from users.\n\nInsecure patterns:\n\n* `open(os.path.join(MEDIA_ROOT, request.GET[\"path\"]))`\n* Download endpoints that take `?file=../../...` style parameters.\n* Misconfigured `MEDIA_ROOT == STATIC_ROOT`.\n\nDetection hints:\n\n* Grep for `open(`, `Path(`, `os.path.join(` used with request values.\n* Check `MEDIA_ROOT`, `STATIC_ROOT` in settings. ([Django Project][3])\n\nFix:\n\n* Use server-side IDs mapped to known files.\n* Keep static and media separated and ensure the web server treats media as untrusted. ([Django Project][3])\n\n---\n\n### DJANGO-REDIRECT-001: Prevent open redirects (`next`, `return_to`, `redirect`)\n\nSeverity: Medium (High when combined with auth flows)\n\nRequired:\n\n* MUST validate redirect targets derived from untrusted input (e.g., `next`, `return_to`).\n* SHOULD restrict to same-site relative paths or allowlisted hosts/schemes.\n* SHOULD use Django’s safe URL helpers (e.g., `django.utils.http.url_has_allowed_host_and_scheme`) rather than custom parsing.\n\nInsecure patterns:\n\n* `return redirect(request.GET.get(\"next\"))` with no validation.\n* Redirect allowlist implemented with naive string checks.\n\nDetection hints:\n\n* Search for `redirect(` and track origin of the target.\n* Search for parameters named `next`, `return_to`, `redirect`, `url`.\n\nFix:\n\n* Validate with allowlists and default to a safe internal path if validation fails.\n* Ensure host validation via `ALLOWED_HOSTS` remains strict (see DJANGO-HOST-001). ([Django Project][3])\n\n---\n\n### DJANGO-HEADERS-001: Enable essential security headers (SecurityMiddleware + clickjacking protection)\n\nSeverity: Medium to High\n\nRequired:\n\n* SHOULD use `django.middleware.security.SecurityMiddleware` and configure it appropriately (production) for:\n\n  * `X-Content-Type-Options: nosniff` (Django setting `SECURE_CONTENT_TYPE_NOSNIFF`, default `True`). ([Django Project][3])\n  * `Referrer-Policy` (Django setting `SECURE_REFERRER_POLICY`, default `'same-origin'`). ([Django Project][3])\n  * COOP (Django setting `SECURE_CROSS_ORIGIN_OPENER_POLICY`, default `'same-origin'`). ([Django Project][3])\n  * HTTPS redirects and HSTS as appropriate (see DJANGO-HTTPS-001). ([Django Project][3])\n* SHOULD enable clickjacking protection via X-Frame-Options middleware; Django security docs strongly recommend it for sites that don’t need third-party framing. ([Django Project][2])\n\nInsecure patterns:\n\n* Missing SecurityMiddleware.\n* Missing clickjacking protection (or disabling it globally) without a clear framing requirement.\n* Over-broad framing allowances for sensitive endpoints.\n\nDetection hints:\n\n* Inspect `MIDDLEWARE` for SecurityMiddleware and XFrameOptionsMiddleware.\n* Search for per-view disabling of framing/CSRF protections.\n\nFix:\n\n* Add/enable middleware and configure the settings intentionally. ([Django Project][3])\n\nNOTE:\n\n* Some headers may be set at the edge (CDN/reverse proxy). If not visible in app code, flag as “verify at edge”.\n\n---\n\n### DJANGO-CSP-001: Deploy a Content Security Policy (CSP) as defense-in-depth\n\nSeverity: Medium (High for apps rendering untrusted content)\n\nNOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n\nRequired:\n\n* SHOULD deploy a CSP to mitigate XSS and content injection classes; Django’s security docs recommend CSP and note it is new in Django 6.0. ([Django Project][2])\n* MUST understand CSP limitations:\n\n  * Avoid excluding routes from CSP coverage; Django warns that an unprotected page can undermine protected pages due to same-origin policy. ([Django Project][2])\n* MAY start with `SECURE_CSP_REPORT_ONLY` to iterate safely (Django provides report-only support). ([Django Project][3])\n\nInsecure patterns:\n\n* No CSP on apps that render user-controlled content.\n* CSP excludes “just a couple pages” (weakens overall protection), especially pages with any injection surface. ([Django Project][2])\n* CSP uses overly permissive directives (e.g., widespread `unsafe-inline`) without justification.\n\nDetection hints:\n\n* Search `SECURE_CSP`, `SECURE_CSP_REPORT_ONLY`, and CSP middleware configuration.\n* Inspect reverse proxy/CDN config for CSP headers.\n\nFix:\n\n* Implement a realistic CSP, ideally report-only first, then enforce. ([Django Project][3])\n\n---\n\n### DJANGO-AUTH-001: Password storage must use Django’s secure hashers; password policy must be configured\n\nSeverity: High\n\nRequired:\n\n* MUST use Django’s built-in password hashing (never store plaintext or reversible encrypted passwords).\n* SHOULD prefer modern hashers and keep defaults updated; Django documents `PASSWORD_HASHERS` and includes modern options (Argon2, bcrypt, scrypt, PBKDF2 variants). ([Django Project][3])\n* SHOULD configure `AUTH_PASSWORD_VALIDATORS` (default is empty) for production password policy. ([Django Project][3])\n\nInsecure patterns:\n\n* Custom password storage or hashing.\n* Plaintext passwords stored in DB fields.\n* No password validation on consumer-facing apps.\n\nDetection hints:\n\n* Search for `.set_password(` usage vs manual hashing.\n* Inspect settings for `PASSWORD_HASHERS` and `AUTH_PASSWORD_VALIDATORS`. ([Django Project][3])\n\nFix:\n\n* Use Django auth user model APIs.\n* Enable password validators appropriate to the product’s risk profile. ([Django Project][3])\n\n---\n\n### DJANGO-AUTHZ-001: Authorization must be explicit and consistent\n\nSeverity: High\n\nRequired:\n\n* MUST enforce authorization checks on every privileged action (view, modify, admin-like operations).\n* MUST NOT rely on UI-only restrictions (e.g., hiding buttons) without server-side permission checks.\n* SHOULD use Django’s permissions/groups and per-object authorization patterns where applicable.\n\nInsecure patterns:\n\n* Views that assume “user is logged in” implies “user may do action”.\n* Missing authorization checks on update/delete endpoints.\n\nDetection hints:\n\n* Enumerate views that modify state; ensure they validate ownership/permission.\n* Look for use of only `is_authenticated` or only `is_staff` without checking object-level access.\n\nFix:\n\n* Add explicit permission checks and tests for unauthorized access.\n\n---\n\n### DJANGO-ADMIN-001: Django admin must be treated as a high-value target\n\nSeverity: High\n\nRequired:\n\n* MUST ensure admin is protected by strong authentication and HTTPS-only transport (see DJANGO-HTTPS-001). ([Django Project][1])\n* SHOULD restrict admin exposure (network allowlists, VPN, SSO, or additional authentication controls) when possible.\n* SHOULD audit installed admin extensions and third-party apps for XSS/CSRF exposure.\n\nInsecure patterns:\n\n* Admin exposed to the internet with weak authentication.\n* Admin served over HTTP.\n\nDetection hints:\n\n* Search `urlpatterns` for `admin.site.urls`.\n* Check deployment config for IP allowlisting or auth gateways.\n\nFix:\n\n* Add network controls and enforce HTTPS.\n\n---\n\n### DJANGO-LOG-001: Logging and error reporting must not leak secrets\n\nSeverity: Medium to High\n\nRequired:\n\n* MUST NOT log secrets (including `SECRET_KEY`, session cookies, auth headers, password reset tokens).\n* MUST configure production logging deliberately; Django’s deployment checklist explicitly calls out reviewing logging before production. ([Django Project][1])\n* MUST ensure `DEBUG=False` in production so exceptions aren’t rendered with sensitive context. ([Django Project][1])\n\nInsecure patterns:\n\n* Logging full request headers or cookies in production.\n* Printing settings dictionaries.\n* Debug error pages.\n\nDetection hints:\n\n* Inspect `LOGGING` config; search for middleware that logs request headers/cookies.\n* Grep for `print(settings` / `logging.info(request.META)` patterns.\n\nFix:\n\n* Redact sensitive values; log IDs not secrets.\n* Use structured logging and a safe error monitoring tool. ([Django Project][1])\n\n---\n\n### DJANGO-SUPPLY-001: Dependency and patch hygiene (Django + security-critical deps)\n\nSeverity: Medium (High if known vulnerable versions)\n\nRequired:\n\n* SHOULD pin and regularly update Django and security-critical dependencies.\n* MUST respond to Django security releases promptly.\n\nDetection hints:\n\n* Check `requirements.txt`, lockfiles, build images.\n* Identify Django version; compare against latest supported release (Django’s download page publishes current stable and supported branches). ([Django Project][9])\n\nFix:\n\n* Upgrade to patched versions; add regression tests for previously vulnerable classes.\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* Deployment/dev server:\n\n  * `manage.py runserver`, `runserver 0.0.0.0`, `--insecure` ([Django Project][1])\n* Debug / settings:\n\n  * `DEBUG = True` ([Django Project][1])\n  * `SECRET_KEY =`, `SECRET_KEY_FALLBACKS` ([Django Project][1])\n* Host validation:\n\n  * `ALLOWED_HOSTS = ['*']` ([Django Project][3])\n* HTTPS and proxy:\n\n  * `SECURE_SSL_REDIRECT`, `SECURE_HSTS_SECONDS`, `SECURE_PROXY_SSL_HEADER` ([Django Project][3])\n* Cookies / sessions:\n\n  * `SESSION_COOKIE_SECURE`, `SESSION_COOKIE_HTTPONLY`, `SESSION_COOKIE_SAMESITE` ([Django Project][3])\n  * `CSRF_COOKIE_SECURE`, `CSRF_COOKIE_HTTPONLY`, `CSRF_COOKIE_SAMESITE` ([Django Project][3])\n* CSRF bypasses:\n\n  * `csrf_exempt`, missing `CsrfViewMiddleware`, POST forms without `{% csrf_token %}` ([Django Project][4])\n* XSS:\n\n  * `|safe`, `autoescape off`, `mark_safe(`, HTML string concatenation ([Django Project][5])\n* SQL injection:\n\n  * `.raw(`, `.extra(`, `RawSQL(`, `cursor.execute(` with formatted SQL strings ([Django Project][7])\n* User uploads / media:\n\n  * `request.FILES`, `MEDIA_ROOT`, `MEDIA_URL`, serving media inline; `MEDIA_ROOT == STATIC_ROOT` ([Django Project][1])\n* Redirects:\n\n  * `redirect(request.GET.get(\"next\"))` patterns; missing allowlist validation\n* Security headers and CSP:\n\n  * Missing `SecurityMiddleware`, missing X-Frame-Options protection, missing `SECURE_CSP` adoption (where appropriate) ([Django Project][2])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (template/SQL/subprocess/files/redirect/http)\n* protective controls present (middleware, validation, allowlists, authz checks)\n* whether security headers/controls are set in-app vs at the edge\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary Django documentation:\n\n```text\n- Django Downloads (current stable & supported branches): https://www.djangoproject.com/download/\n- Django 6.0 Release Notes: https://docs.djangoproject.com/en/6.0/releases/6.0/\n- Django: Deployment checklist (incl. check --deploy, runserver warning, HTTPS/cookies guidance): https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/\n- Django: Settings reference (SecurityMiddleware settings, cookies, SECRET_KEY_FALLBACKS, CSP settings): https://docs.djangoproject.com/en/6.0/ref/settings/\n- Django: Security in Django (XSS/CSRF/SQLi/clickjacking/HTTPS/host header validation/uploads/CSP): https://docs.djangoproject.com/en/6.0/topics/security/\n- Django: CSRF how-to (middleware, csrf_token usage, AJAX header patterns, csrf_exempt cautions): https://docs.djangoproject.com/en/6.0/howto/csrf/\n- Django: Performing raw SQL queries (parameterization guidance): https://docs.djangoproject.com/en/6.0/topics/db/sql/\n- Django: QuerySet API reference (extra() cautions; “do not quote placeholders” guidance): https://docs.djangoproject.com/en/6.0/ref/models/querysets/\n- Django: Template built-ins (autoescape tag): https://docs.djangoproject.com/en/6.0/ref/templates/builtins/\n- Django: Template language reference (turning off autoescape & risks): https://docs.djangoproject.com/en/6.0/ref/templates/language/\n- Django: Utilities reference (e.g., format_html): https://docs.djangoproject.com/en/6.0/ref/utils/\n```\n\nOWASP:\n\n```text\n- OWASP Cheat Sheet Series: Django Security Cheat Sheet: https://cheatsheetseries.owasp.org/cheatsheets/Django_Security_Cheat_Sheet.html\n```\n\n[1]: https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/ \"https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/\"\n[2]: https://docs.djangoproject.com/en/6.0/topics/security/ \"Security in Django | Django documentation | Django\"\n[3]: https://docs.djangoproject.com/en/6.0/ref/settings/ \"Settings | Django documentation | Django\"\n[4]: https://docs.djangoproject.com/en/6.0/howto/csrf/ \"How to use Django’s CSRF protection | Django documentation | Django\"\n[5]: https://docs.djangoproject.com/en/6.0/ref/templates/builtins/ \"https://docs.djangoproject.com/en/6.0/ref/templates/builtins/\"\n[6]: https://docs.djangoproject.com/en/6.0/ref/utils/ \"https://docs.djangoproject.com/en/6.0/ref/utils/\"\n[7]: https://docs.djangoproject.com/en/6.0/topics/db/sql/ \"https://docs.djangoproject.com/en/6.0/topics/db/sql/\"\n[8]: https://docs.djangoproject.com/en/6.0/ref/models/querysets/ \"https://docs.djangoproject.com/en/6.0/ref/models/querysets/\"\n[9]: https://www.djangoproject.com/download/ \"Download Django | Django\"\n","core/skills/builtin/security-best-practices/references/python-fastapi-web-server-security.md":"# FastAPI (Python) Web Security Spec (FastAPI 0.128.x, Python 3.x) ([PyPI][1])\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new FastAPI code.\n2. **Security review / vulnerability hunting** in existing FastAPI code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\nFastAPI is commonly deployed with an ASGI server (e.g., Uvicorn) and is built on Starlette + Pydantic, so this spec covers those layers where they affect security. ([PyPI][1])\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session cookies, signing keys, database URLs with credentials).\n* MUST NOT “fix” security by disabling protections (e.g., weakening auth, making CORS permissive, skipping signature checks, disabling validation, turning off TLS verification, adding `allow_origins=[\"*\"]` with credentials).\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and configuration values that justify the claim.\n* MUST treat uncertainty honestly: if a protection might exist in infrastructure (reverse proxy, WAF, CDN, service mesh), report it as “not visible in app code; verify at runtime/config”.\n* MUST treat browser controls correctly:\n\n  * CORS is **not** an auth mechanism; it only affects browsers.\n  * CSRF defenses apply when the browser automatically attaches credentials (cookies); they are usually not relevant for purely header-token APIs. ([OWASP Cheat Sheet Series][2])\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new FastAPI code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default APIs and proven libraries over custom security code.\n* MUST avoid introducing new risky sinks (shell execution, unsafe deserialization, dynamic eval, untrusted template rendering, unsafe file serving, unsafe redirects, arbitrary outbound fetching).\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a FastAPI repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. App entrypoints / deployment scripts / Dockerfiles / Procfiles / Helm/terraform.\n2. ASGI server configuration (Uvicorn/Gunicorn), proxy settings, debug/reload settings.\n3. FastAPI app configuration (docs exposure, middleware, trusted hosts, CORS).\n4. Authn/Authz design (dependencies, JWT/session handling, password storage).\n5. Cookie/session usage + CSRF (if cookies are used).\n6. Input validation and output shaping (Pydantic models, mass assignment, excessive data exposure).\n7. Template rendering and XSS/SSTI (if HTML is served).\n8. File handling (uploads + downloads), StaticFiles, Range support.\n9. Injection classes (SQL, command execution, unsafe deserialization).\n10. Outbound requests (SSRF), redirect handling, WebSockets security.\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nExamples include:\n\n* Query parameters / path parameters\n* JSON bodies (including nested fields)\n* Headers (including `Host`, `Origin`, `X-Forwarded-*`)\n* Cookies (including session cookies)\n* File uploads (multipart parts)\n* WebSocket messages, query params, and headers during handshake ([Starlette][3])\n* Any data from external systems (webhooks, third-party APIs, message queues)\n* Any persisted user content (DB rows) that originated from users\n\n### 2.2 State-changing request\n\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook send), or initiate privileged actions.\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + function/route name + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common FastAPI/ASGI misconfigurations.\n\nBaseline goals:\n\n* No debug tracebacks or auto-reload in production. ([PyPI][4])\n* Run under a production ASGI server configuration (workers, timeouts, resource controls). ([PyPI][4])\n* Host header validation enabled (TrustedHostMiddleware or equivalent). ([PyPI][5])\n* CORS disabled unless explicitly needed; if enabled, it is strict and least-privilege. ([OWASP Cheat Sheet Series][6])\n* Auth is enforced consistently via dependencies (no “oops, forgot auth on this route”). ([FastAPI][7])\n* If cookies/sessions are used, cookie flags are secure and CSRF is addressed. ([OWASP Cheat Sheet Series][8])\n* Request size limits and multipart limits exist at the edge and are validated in app as needed (to mitigate memory/CPU DoS). ([advisories.gitlab.com][9])\n* Dependencies are patched promptly, especially Starlette/python-multipart (multiple DoS and traversal advisories exist historically). ([advisories.gitlab.com][10])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### FASTAPI-DEPLOY-001: Do not use auto-reload / dev-only server modes in production\n\nSeverity: High (if production)\n\nRequired:\n\n* MUST NOT run production using auto-reload/watch mode (e.g., Uvicorn reload).\n* MUST run with a production process model (e.g., multiple workers where appropriate) and stable server settings. ([PyPI][4])\n\nInsecure patterns:\n\n* `uvicorn ... --reload` (or equivalent “reload=True” configs) in production entrypoints.\n* Docker/Procfile/systemd commands that run with `--reload` in production.\n\nDetection hints:\n\n* Search for `--reload`, `reload=True`, `watchfiles`, `fastapi dev`, “development” run scripts.\n* Check Docker CMD/ENTRYPOINT, Procfile, systemd units, shell scripts.\n\nFix:\n\n* Remove reload in production; run Uvicorn/Gunicorn with stable settings and explicit worker configuration. ([PyPI][4])\n\nNote:\n\n* Reload is fine for local development. Only flag when it is clearly used as a production entrypoint.\n\n---\n\n### FASTAPI-DEPLOY-002: Debug mode MUST be disabled in production\n\nSeverity: Critical\n\nRequired:\n\n* MUST NOT enable debug tracebacks in production (FastAPI/Starlette debug mode can expose sensitive internals and make some exploit chains easier). ([PyPI][5])\n* MUST treat any configuration that returns detailed stack traces to clients as sensitive.\n\nInsecure patterns:\n\n* `app = FastAPI(debug=True)` (or Starlette `debug=True`), or equivalent environment toggles enabling debug in production. ([PyPI][5])\n* Server/log config that exposes tracebacks to end users.\n\nDetection hints:\n\n* Search for `debug=True`, `DEBUG = True`, environment flags mapped to debug.\n* Review exception middleware and error handler setup.\n\nFix:\n\n* Ensure debug is only enabled in local dev/test.\n* Return generic error responses to clients; log details internally.\n\n---\n\n### FASTAPI-OPENAPI-001: OpenAPI and interactive docs MUST be disabled or protected in production\n\nSeverity: Medium (can be High in sensitive/internal apps)\n\nRequired:\n\n* SHOULD disable `/docs`, `/redoc`, and `/openapi.json` in production for public-facing services unless there is an explicit business need.\n* If enabled, MUST protect them (e.g., auth, network allowlists, or internal-only routing).\n* MUST NOT assume “security through obscurity”; treat docs exposure as an information disclosure amplifier.\n\nInsecure patterns:\n\n* Publicly reachable `/docs` and `/openapi.json` for internal/admin APIs.\n* Docs enabled on the same hostname as production without access control.\n\nDetection hints:\n\n* Look for `FastAPI(docs_url=..., redoc_url=..., openapi_url=...)` or defaults.\n* Check reverse proxy routing and allowlists.\n\nFix:\n\n* Disable docs endpoints in prod (`docs_url=None`, `redoc_url=None`, `openapi_url=None`) or restrict access at the edge.\n\n---\n\n### FASTAPI-AUTH-001: Authentication MUST be explicit and consistently enforced via dependencies\n\nSeverity: High\n\nRequired:\n\n* MUST implement authentication as a dependency (or router-level dependency) so that protected endpoints cannot “forget” auth.\n* MUST default to “deny” for privileged routers/endpoints; explicitly mark truly public routes.\n* SHOULD centralize auth enforcement at router boundaries (e.g., protected `APIRouter` for authenticated endpoints). ([FastAPI][7])\n\nInsecure patterns:\n\n* Per-route ad-hoc auth checks scattered through handlers (easy to miss).\n* A mix of protected/unprotected endpoints with no clear policy.\n\nDetection hints:\n\n* Identify routers and endpoints; check whether protected ones include `Depends(...)`/`Security(...)`.\n* Search for patterns like `if user is None: raise ...` inside handlers (instead of dependencies).\n\nFix:\n\n* Move authentication into a dependency and attach it to the router/endpoint consistently using `Depends()`/`Security()`. ([FastAPI][7])\n\n---\n\n### FASTAPI-AUTH-002: Use standard auth transports; avoid secrets in URLs\n\nSeverity: High\n\nRequired:\n\n* SHOULD use the `Authorization: Bearer <token>` header for token auth, not query parameters. ([FastAPI][11])\n* MUST NOT place secrets (tokens, reset links containing long-lived secrets, API keys) in query strings when avoidable.\n\nInsecure patterns:\n\n* `?token=...`, `?api_key=...`, `?auth=...` used for primary auth.\n* Long-lived access tokens embedded in URLs (leak via logs, referrers, caches).\n\nDetection hints:\n\n* Search for parameter names like `token`, `api_key`, `key`, `secret`, `password`.\n* Look for security schemes that use query API keys without justification.\n\nFix:\n\n* Move tokens to Authorization headers; rotate/shorten lifetimes; use POST bodies for sensitive values.\n\n---\n\n### FASTAPI-AUTH-003: Password storage MUST be strongly hashed; never store plaintext passwords\n\nSeverity: Critical\n\nRequired:\n\n* MUST store passwords using a strong, slow password hashing scheme (e.g., Argon2id, bcrypt).\n* MUST NOT store plaintext passwords, or reversible encryption as the primary protection.\n* SHOULD use established libraries for hashing and verification (do not roll your own).\n\nInsecure patterns:\n\n* Storing plaintext passwords in DB.\n* Using fast hashes (e.g., SHA256) without a proper password hashing KDF.\n* Returning password hashes in API responses.\n\nDetection hints:\n\n* Search for `password=` persisted fields, and look for `hashlib.md5/sha1/sha256` usage on passwords.\n* Inspect response models for password/hash fields.\n\nFix:\n\n* Migrate to a proper password hashing library; add a re-hash-on-login upgrade path.\n\n---\n\n### FASTAPI-AUTH-004: JWT validation MUST be strict; JWTs MUST NOT carry secrets\n\nSeverity: High\n\nRequired:\n\n* MUST validate JWT signature and enforce an algorithm allowlist.\n* MUST validate standard claims appropriate to your system (at least `exp`; typically also `iss`/`aud` if multi-service or multi-tenant).\n* MUST treat JWT contents as readable by the client; do not put secrets in JWT payloads. ([FastAPI][12])\n\nInsecure patterns:\n\n* `jwt.decode(..., options={\"verify_signature\": False})` or equivalent.\n* Accepting `alg=none` / algorithm confusion.\n* Using JWT payload to store sensitive secrets (API keys, passwords).\n\nDetection hints:\n\n* Search for `jwt.decode`, `python-jose`, `PyJWT`, `verify_signature`.\n* Check for missing exp validation or long expirations.\n\nFix:\n\n* Enforce strict validation (signature, allowed algorithms, exp, and any required issuer/audience constraints).\n* Store only identifiers/claims you are comfortable exposing to the client. ([FastAPI][12])\n\n---\n\n### FASTAPI-AUTHZ-001: Authorization MUST be enforced per-object and per-property\n\nSeverity: High\n\nRequired:\n\n* MUST perform object-level authorization whenever accessing a resource by user-controlled identifier (ID in path/query/body).\n* MUST perform property-level authorization and response shaping to prevent “excessive data exposure” (e.g., admin-only fields). ([OWASP Foundation][13])\n\nInsecure patterns:\n\n* `GET /users/{id}` returns user record without verifying caller can access that `id`.\n* Response models include internal fields (roles, permissions, billing data, password hashes).\n\nDetection hints:\n\n* Enumerate endpoints that accept IDs; trace whether an authz check is performed.\n* Compare response models for public vs internal fields.\n\nFix:\n\n* Add object-level checks (ownership, ACLs, tenant boundaries).\n* Use dedicated response models that include only allowed fields.\n\n---\n\n### FASTAPI-SESS-001: If using cookie-based sessions and TLS, cookie attributes MUST be secure in production\n\nSeverity: High (only if TLS is enabled)\n\nRequired (production, HTTPS):\n\n* MUST set session cookies to be sent only over HTTPS (secure). IMPORTANT NOTE: Only set `Secure` in production environment when TLS is configured. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n* MUST set HttpOnly for session cookies (not accessible to JS).\n* SHOULD use `SameSite=Lax` (or `Strict` if UX allows); if you require cross-site cookies, document the CSRF implications and add compensating controls. ([OWASP Cheat Sheet Series][8])\n* If using Starlette `SessionMiddleware`, MUST set `https_only=True` in production and choose an appropriate `same_site`. ([PyPI][5])\n\nInsecure patterns:\n\n* Session cookies without Secure/HttpOnly.\n* `SameSite=None` cookies used for authenticated state-changing endpoints without CSRF protections.\n\nDetection hints:\n\n* Search for `SessionMiddleware(` and inspect parameters like `https_only`, `same_site`.\n* Search for `set_cookie(` usage and cookie flags.\n\nFix:\n\n* Set secure cookie attributes; prefer short lifetimes for high-privilege sessions. ([OWASP Cheat Sheet Series][8])\n\n---\n\n### FASTAPI-SESS-002: Do not store sensitive secrets in signed session cookies\n\nSeverity: High\n\nRequired:\n\n* MUST assume cookie-based session data is readable by the client (signed ≠ encrypted); do not store secrets/PII unless encrypted server-side.\n* Store only opaque identifiers (e.g., session ID) or non-sensitive state in the cookie; store sensitive session state server-side. ([OWASP Cheat Sheet Series][8])\n\nInsecure patterns:\n\n* Storing access tokens, refresh tokens, or PII directly in cookie session payloads.\n* Treating “signed cookies” as confidential storage.\n\nDetection hints:\n\n* Search for `request.session[...] =` or `session[...] =`-equivalent patterns; identify what is stored.\n* Identify use of `SessionMiddleware` or other cookie session mechanisms.\n\nFix:\n\n* Move sensitive values to server-side storage; keep cookie minimal.\n\n---\n\n### FASTAPI-CSRF-001: Cookie-authenticated state-changing requests MUST be CSRF-protected\n\nSeverity: High\n\nNote: This only applies if using cookie based auth. If the application uses header or token based auth such as Authorization header, then CSRF is not an issue.\n\nRequired:\n\n* MUST protect all state-changing endpoints (POST/PUT/PATCH/DELETE) that rely on cookies for authentication.\n* SHOULD use a proven CSRF approach (synchronizer token pattern, or well-reviewed middleware) rather than rolling your own. ([OWASP Cheat Sheet Series][2])\n* MAY add defense-in-depth (Origin/Referer checks, SameSite cookies, Fetch Metadata), but tokens are the primary defense for cookie-authenticated apps. ([OWASP Cheat Sheet Series][2])\n* IMPORTANT NOTE: If cookies are not used for auth (auth is via `Authorization` header), CSRF is usually not applicable. ([FastAPI][11])\n\nInsecure patterns:\n\n* Cookie-authenticated endpoints that change state with no CSRF validation.\n* Using GET for state-changing actions (amplifies CSRF risk).\n\nDetection hints:\n\n* Enumerate routes with methods other than GET; identify whether cookies are used for auth.\n* Look for CSRF token generation/verification or middleware.\n\nFix:\n\n* Add CSRF tokens (and validate them) on state-changing actions when cookie auth is in use. ([OWASP Cheat Sheet Series][2])\n\n---\n\n### FASTAPI-VALID-001: Request parsing and validation MUST be schema-driven; prevent mass assignment\n\nSeverity: Medium (especially for APIs that write to DB)\n\nRequired:\n\n* SHOULD use Pydantic models for request bodies instead of accepting arbitrary `dict`/`Any`.\n* SHOULD configure models to reject unexpected fields where appropriate (prevents “mass assignment” style bugs).\n* MUST validate and normalize identifiers (IDs, email, URLs) before using them for access control or side effects. ([OWASP Cheat Sheet Series][14])\n\nInsecure patterns:\n\n* `payload = await request.json()` followed by `Model(**payload)` or direct DB writes with `payload` (no allowlist).\n* Models that silently accept unknown fields for write endpoints.\n\nDetection hints:\n\n* Search for `await request.json()`, `request.body()`, `dict`-typed bodies, `Any`-typed bodies.\n* Look for endpoints that do `db.update(**payload)` or `Model(**payload)` with unfiltered input.\n\nFix:\n\n* Use explicit Pydantic models with allowlisted fields; reject extras for write endpoints. ([OWASP Cheat Sheet Series][14])\n\n---\n\n### FASTAPI-RESP-001: Prevent excessive data exposure via response models and explicit serialization\n\nSeverity: Medium\n\nRequired:\n\n* MUST define response models that include only intended fields (especially for user objects, auth-related objects, billing objects).\n* SHOULD use separate models for “create input”, “db/internal”, and “public output” to avoid leaking sensitive fields. ([FastAPI][15])\n\nInsecure patterns:\n\n* Returning ORM objects or dicts that include internal columns.\n* Reusing “DB model” as the response model (includes `password_hash`, `is_admin`, etc).\n\nDetection hints:\n\n* Look for endpoints that `return user` where `user` is an ORM instance.\n* Check for `response_model` omissions on endpoints that return sensitive resources.\n\nFix:\n\n* Add explicit response models; create “public” schemas that exclude sensitive fields. ([FastAPI][15])\n\n---\n\n### FASTAPI-XSS-001: Prevent reflected/stored XSS in HTML responses and templates\n\nSeverity: High (if the service serves HTML)\n\nRequired:\n\n* MUST use templating with auto-escaping enabled for HTML.\n* MUST NOT mark untrusted content as safe (no unsafe “raw HTML” rendering of user-controlled data).\n* SHOULD deploy a CSP when serving HTML that includes any user content. ([OWASP Cheat Sheet Series][16])\n\nInsecure patterns:\n\n* Rendering user content directly into HTML without escaping/sanitization.\n* Disabling auto-escaping or using “raw HTML” features without sanitization.\n\nDetection hints:\n\n* Search for template rendering and string concatenation that builds HTML.\n* Review templates for “unsafe” filters/constructs and unquoted attributes.\n\nFix:\n\n* Keep auto-escaping on; sanitize user HTML only if absolutely required using a trusted sanitizer; add CSP. ([OWASP Cheat Sheet Series][16])\n\nNote:\n\n* If the app is a pure JSON API, XSS is usually a client/app concern, but error pages/docs pages might still render HTML.\n\n---\n\n### FASTAPI-SSTI-001: Never render untrusted templates (Server-Side Template Injection)\n\nSeverity: Critical\n\nRequired:\n\n* MUST NOT render templates that contain user-controlled template syntax.\n* MUST treat “template-from-string” rendering as dangerous if influenced by untrusted input.\n* If untrusted templates are absolutely required (rare, high-risk):\n\n  * MUST use a sandboxed templating approach and restrict capabilities.\n  * MUST assume sandbox escapes are possible; add isolation and strict allowlists. ([OWASP Foundation][17])\n\nInsecure patterns:\n\n* Rendering templates loaded from user input or DB via a normal Jinja environment.\n* Building templates dynamically using user-controlled strings.\n\nDetection hints:\n\n* Grep for Jinja `Environment.from_string`, `Template(...)`, or similar.\n* Trace origin of template string (request, DB, uploads, admin panels).\n\nFix:\n\n* Replace with non-executable templating (simple string substitution).\n* If truly needed, use Jinja’s sandbox environment plus strong isolation. ([jinja.palletsprojects.com][18])\n\n---\n\n### FASTAPI-HEADERS-001: Set essential security headers (in app or at the edge)\n\nSeverity: Medium\n\nRequired (typical API/web app):\n\n* SHOULD set:\n\n  * `X-Content-Type-Options: nosniff`\n  * Clickjacking protection (`X-Frame-Options` and/or CSP `frame-ancestors`) if HTML is served\n  * `Referrer-Policy` and `Permissions-Policy` as appropriate\n\nNOTE:\n\n* Headers may be set by a proxy/CDN. If not visible in app code, flag as “verify at edge”. ([OWASP Cheat Sheet Series][6])\n\nInsecure patterns:\n\n* No security headers anywhere (app or edge) for apps serving HTML or sensitive APIs.\n\nDetection hints:\n\n* Search for middleware that sets headers; check reverse proxy config.\n\nFix:\n\n* Set headers centrally (middleware) or via reverse proxy/CDN.\n\n---\n\n### FASTAPI-CORS-001: CORS MUST be explicit and least-privilege\n\nSeverity: Medium (High if misconfigured with credentials)\n\nRequired:\n\n* If CORS is not needed, MUST keep it disabled.\n* If CORS is needed:\n\n  * MUST allowlist trusted origins (do not reflect arbitrary origins).\n  * MUST NOT combine credentialed requests with wildcard origins (this is unsafe and commonly rejected by compliant middleware). ([OWASP Cheat Sheet Series][6])\n  * SHOULD restrict allowed methods and headers.\n\nInsecure patterns:\n\n* `allow_origins=[\"*\"]` together with `allow_credentials=True`.\n* Reflecting `Origin` without validation.\n* `allow_origin_regex=\".*\"` used broadly.\n\nDetection hints:\n\n* Search for `CORSMiddleware` configuration.\n* Look for `allow_origins=[\"*\"]`, `allow_credentials=True`, `allow_origin_regex`.\n\nFix:\n\n* Use an explicit origin allowlist and minimal methods/headers; keep credentials off unless required. ([OWASP Cheat Sheet Series][6])\n\n---\n\n### FASTAPI-HOST-001: Host header MUST be validated in production\n\nSeverity: Low\n\nRequired:\n\n* SHOULD use `TrustedHostMiddleware` (or equivalent at edge) to restrict accepted Host values. ([PyPI][5])\n* MUST NOT trust the `Host` header for security-sensitive decisions without validation.\n\nInsecure patterns:\n\n* No Host validation while generating external URLs (password reset links, callback URLs) from request host.\n* Allowing arbitrary Host headers in apps behind permissive proxies.\n\nDetection hints:\n\n* Search for `TrustedHostMiddleware` usage.\n* Search for logic that uses `request.url`, `request.base_url`, or host-derived values to build external URLs.\n\nFix:\n\n* Configure a strict allowed-hosts list in production; enforce at edge too if possible.\n\n---\n\n### FASTAPI-PROXY-001: Reverse proxy trust MUST be configured correctly\n\nSeverity: High (when behind a proxy)\n\nRequired:\n\n* If behind a reverse proxy, MUST configure forwarded-header trust correctly.\n* MUST NOT blindly trust `X-Forwarded-*` headers from the open internet.\n* If using Uvicorn proxy header support, MUST restrict which IPs are allowed to provide forwarded headers. ([PyPI][4])\n\nInsecure patterns:\n\n* Enabling proxy headers broadly without restricting trusted proxy IPs.\n* Using forwarded headers to decide “is secure” / “is internal” / “client IP” without proper trust boundaries.\n\nDetection hints:\n\n* Search for `--proxy-headers`, `--forwarded-allow-ips`, or equivalent config.\n* Search for security-sensitive use of `request.client.host`, `request.url.scheme`, `request.headers[\"x-forwarded-for\"]`.\n\nFix:\n\n* Configure Uvicorn with proxy headers only when behind a known proxy, and restrict `forwarded_allow_ips` to that proxy. ([PyPI][4])\n* Keep Host allowlisting in place even behind proxies.\n\n---\n\n### FASTAPI-LIMITS-001: Request and multipart limits MUST be enforced to prevent DoS\n\nSeverity: Low\n\nRequired:\n\n* MUST enforce request size limits at the edge (reverse proxy/load balancer) and validate in app where needed.\n* MUST apply special scrutiny to multipart/form-data handling; historical vulnerabilities include unbounded buffering and DoS vectors. ([advisories.gitlab.com][9])\n* SHOULD rate limit and/or add per-IP/per-user throttles for expensive endpoints.\n\nInsecure patterns:\n\n* Accepting arbitrarily large JSON bodies or multipart forms.\n* Parsing multipart forms without size/field-count controls.\n\nDetection hints:\n\n* Identify file upload endpoints and `multipart/form-data` usage.\n* Look for missing proxy-level limits (nginx `client_max_body_size`, ALB limits, etc.) and missing app-level checks.\n\nFix:\n\n* Enforce strict body limits and multipart constraints; keep Starlette and python-multipart updated to patched versions. ([advisories.gitlab.com][9])\n\n---\n\n### FASTAPI-FILES-001: Prevent path traversal and unsafe static file exposure\n\nSeverity: High\n\nRequired:\n\n* MUST NOT pass user-controlled file paths to `FileResponse`/filesystem calls without strict validation and safe base directories.\n* If using `StaticFiles`, MUST keep Starlette updated and understand the security history (path traversal advisory exists for older versions). ([advisories.gitlab.com][10])\n* MUST NOT serve user uploads as executable/active content (especially HTML/JS) from a static root without safe handling.\n\nInsecure patterns:\n\n* `FileResponse(request.query_params[\"path\"])`\n* Mounting `StaticFiles(directory=\"uploads\")` where uploads include HTML/JS/SVG and are served inline.\n\nDetection hints:\n\n* Search for `FileResponse(`, `StaticFiles(`, `open(` in routes.\n* Trace whether the path originates from untrusted input.\n\nFix:\n\n* Use opaque IDs for files; map IDs to server-side stored paths.\n* Serve untrusted content as attachment downloads where appropriate.\n\n---\n\n### FASTAPI-FILES-002: Mitigate Range-header DoS on file-serving endpoints\n\nSeverity: Low (if affected versions and file serving is enabled)\n\nRequired:\n\n* MUST keep Starlette patched against known file-serving DoS issues if using `FileResponse`/`StaticFiles`.\n* MUST treat unusual `Range` header handling and file serving as a DoS surface. ([advisories.gitlab.com][19])\n\nInsecure patterns:\n\n* Serving large files with vulnerable Starlette versions.\n* No rate limiting / CDN shielding for file endpoints.\n\nDetection hints:\n\n* Identify Starlette version; if in affected range, flag.\n* Find uses of `FileResponse` and `StaticFiles`.\n\nFix:\n\n* Upgrade Starlette to a fixed version per advisory guidance. ([advisories.gitlab.com][19])\n* Add edge caching/rate limiting for file endpoints where appropriate.\n\n---\n\n### FASTAPI-UPLOAD-001: File uploads MUST be validated, stored safely, and served safely\n\nSeverity: Medium\n\nRequired:\n\n* MUST enforce upload size limits (app + edge).\n* MUST validate file type using allowlists and content checks (not only extension). ([OWASP Cheat Sheet Series][20])\n* SHOULD generate server-side filenames (random IDs) and avoid trusting original names.\n* MUST serve potentially active formats safely (download attachment) unless explicitly intended.\n\nInsecure patterns:\n\n* Accepting arbitrary file types and serving them back inline.\n* Using user-supplied filename as storage path.\n\nDetection hints:\n\n* Look for upload handlers and where/how files are written.\n* Look for direct exposure of upload directories.\n\nFix:\n\n* Implement allowlist validation + safe storage + safe serving; add scanning/quarantine if applicable. ([OWASP Cheat Sheet Series][20])\n\n---\n\n### FASTAPI-INJECT-001: Prevent SQL injection (use parameterized queries / ORM)\n\nSeverity: High\n\nRequired:\n\n* MUST use parameterized queries or an ORM that parameterizes under the hood.\n* MUST NOT build SQL by string concatenation / f-strings with untrusted input. ([OWASP Cheat Sheet Series][21])\n\nInsecure patterns:\n\n* `f\"SELECT ... WHERE id={user_id}\"`\n* `\"... WHERE name = '%s'\" % user_input`\n\nDetection hints:\n\n* Grep for SQL keywords in Python strings near `.execute(...)`.\n* Trace untrusted data into DB calls.\n\nFix:\n\n* Replace with parameterized queries / ORM query APIs; validate types before querying. ([OWASP Cheat Sheet Series][21])\n\n---\n\n### FASTAPI-INJECT-002: Prevent OS command injection\n\nSeverity: Critical to High (depends on exposure)\n\nRequired:\n\n* MUST avoid executing shell commands with untrusted input.\n* If subprocess is necessary:\n\n  * MUST pass args as a list (not a string)\n  * MUST NOT use `shell=True` with attacker-influenced strings\n  * SHOULD use strict allowlists for any variable component ([OWASP Cheat Sheet Series][22])\n\nInsecure patterns:\n\n* `os.system(user_input)`\n* `subprocess.run(f\"cmd {user}\", shell=True)`\n* Passing user strings into `bash -c`, `sh -c`, PowerShell, etc.\n\nDetection hints:\n\n* Search for `os.system`, `subprocess`, `Popen`, `shell=True`.\n* Trace data from request/DB into these calls.\n\nFix:\n\n* Use library APIs instead of shell commands.\n* If unavoidable, hard-code the command and allowlist validated parameters; use `--` separator where supported. ([OWASP Cheat Sheet Series][22])\n\n---\n\n### FASTAPI-SSRF-001: Prevent server-side request forgery (SSRF) in outbound HTTP\n\nSeverity: Medium (can be High in cloud/VPC environments)\n\n- Note: For small stand alone projects this is less important. It is most important when deploying into an LAN or with other services listening on the same server.\n\nRequired:\n\n* MUST treat outbound requests to user-provided URLs as high risk.\n* SHOULD validate and restrict destinations (allowlist hosts/domains) for any user-influenced URL fetch.\n* SHOULD block access to localhost/private IP ranges/link-local and cloud metadata endpoints.\n* MUST restrict protocols to http/https.\n* SHOULD set timeouts and carefully control redirects. ([OWASP Cheat Sheet Series][23])\n\nInsecure patterns:\n\n* `httpx.get(request.query_params[\"url\"])`\n* “URL preview/import/webhook tester” features that accept arbitrary URLs.\n\nDetection hints:\n\n* Search for `requests`, `httpx`, `urllib`, `aiohttp` calls with URLs derived from requests/DB.\n* Identify endpoints named `fetch`, `preview`, `proxy`, `webhook`, `import`.\n\nFix:\n\n* Implement strict URL parsing + allowlists; add egress controls; set short timeouts; disable redirects if not required. ([OWASP Cheat Sheet Series][23])\n\n---\n\n### FASTAPI-REDIRECT-001: Prevent open redirects\n\nSeverity: Low\n\nRequired:\n\n* MUST validate redirect targets derived from untrusted input (`next`, `redirect`, `return_to`).\n* SHOULD prefer redirecting only to same-site relative paths or an allowlist of domains. ([OWASP Cheat Sheet Series][24])\n\nInsecure patterns:\n\n* Returning `RedirectResponse(next)` where `next` is user-controlled with no validation.\n\nDetection hints:\n\n* Search for `RedirectResponse(` or redirect logic and examine the source of the target.\n\nFix:\n\n* Allow only relative paths or allowlisted domains; fall back to a safe default. ([OWASP Cheat Sheet Series][24])\n\n---\n\n### FASTAPI-WS-001: WebSocket endpoints MUST be authenticated and protected against cross-site abuse\n\nSeverity: Medium to High (depends on data/privilege)\n\nRequired:\n\n* MUST authenticate WebSocket connections for any non-public channel (WebSockets don’t inherently provide auth). ([OWASP Cheat Sheet Series][25])\n* SHOULD enforce origin/CSRF-like protections appropriate for browser-based WebSocket clients (Origin validation is a common control).\n* SHOULD rate limit message frequency and connection attempts; close idle/abusive connections.\n\nInsecure patterns:\n\n* `@app.websocket(...)` accepts and trusts the connection with no auth check.\n* Using query-string tokens for auth without considering leakage/rotation.\n\nDetection hints:\n\n* Search for `@app.websocket` / `websocket_endpoint` and inspect whether auth is performed before accepting sensitive operations.\n* Review origin checks, token parsing, and per-connection authorization.\n\nFix:\n\n* Require authentication during handshake (e.g., a token or session) and enforce authorization for actions/messages.\n* Validate Origin for browser-based clients where appropriate; apply rate limits and timeouts. ([OWASP Cheat Sheet Series][25])\n\n---\n\n### FASTAPI-SUPPLY-001: Dependency and patch hygiene (focus on security-relevant deps)\n\nSeverity: Low\n\nRequired:\n\n* SHOULD pin and regularly update security-critical dependencies (FastAPI, Starlette, Uvicorn, Pydantic, python-multipart, auth/JWT libs).\n* MUST respond to known security advisories promptly.\n* MUST treat file serving and multipart parsing dependencies as security-sensitive due to historical CVEs. ([advisories.gitlab.com][10])\n\nAudit focus examples (historical):\n\n* Starlette StaticFiles path traversal (fixed in 0.27.0). ([advisories.gitlab.com][10])\n* Starlette multipart/form-data DoS (fixed in 0.40.0). ([advisories.gitlab.com][9])\n* Starlette FileResponse Range header DoS (fixed in 0.49.1). ([advisories.gitlab.com][19])\n\nDetection hints:\n\n* Check `requirements.txt`, lockfiles, container images, and runtime environments for actual installed versions.\n* Map file upload/file serving features to dependency versions.\n\nFix:\n\n* Upgrade to patched versions per advisories; add regression tests around affected behavior.\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* Dev server / debug:\n\n  * `--reload`, `reload=True`, `debug=True`, `FastAPI(debug=True)` ([PyPI][4])\n* OpenAPI/docs exposure:\n\n  * `/docs`, `/redoc`, `/openapi.json`, `docs_url=`, `openapi_url=`\n* Auth enforcement gaps:\n\n  * Endpoints missing `Depends()`/`Security()` where expected; routers without a consistent dependency boundary ([FastAPI][7])\n  * Tokens in query params (`token=`, `api_key=`, `key=`) ([FastAPI][11])\n* Session/cookies + CSRF:\n\n  * `SessionMiddleware(` and cookie flags (`https_only`, `same_site`) ([PyPI][5])\n  * POST/PUT/PATCH/DELETE handlers using cookie auth with no CSRF checks ([OWASP Cheat Sheet Series][2])\n* Input validation & mass assignment:\n\n  * `await request.json()` and direct DB writes from dicts; models accepting extra fields ([OWASP Cheat Sheet Series][14])\n* Excessive data exposure:\n\n  * Returning ORM objects or dicts without `response_model`; responses containing password/role/internal fields ([FastAPI][15])\n* CORS:\n\n  * `CORSMiddleware` with `allow_origins=[\"*\"]`, `allow_origin_regex=\".*\"`, `allow_credentials=True` ([OWASP Cheat Sheet Series][6])\n* Files:\n\n  * `FileResponse(` with user-controlled paths; `StaticFiles(` exposing uploads ([advisories.gitlab.com][10])\n* Uploads / multipart:\n\n  * `multipart/form-data` endpoints with no size/field constraints; outdated Starlette/python-multipart ([advisories.gitlab.com][9])\n* Injection:\n\n  * SQL strings with f-strings/concatenation into `.execute(...)` ([OWASP Cheat Sheet Series][21])\n  * `subprocess.*`, `shell=True`, `os.system` ([OWASP Cheat Sheet Series][22])\n* SSRF:\n\n  * `httpx.get/post` or `requests.*` with URL from request/DB, no allowlist/timeouts ([OWASP Cheat Sheet Series][23])\n* Redirect:\n\n  * `RedirectResponse(next)` with no validation ([OWASP Cheat Sheet Series][24])\n* WebSockets:\n\n  * `@app.websocket` handlers without auth/origin checks; use of `ws://` in prod configs ([FastAPI][27])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (SQL/subprocess/files/template/http/redirect/ws)\n* protective controls present (validation, allowlists, middleware, edge controls)\n* installed dependency versions vs vulnerable ranges ([advisories.gitlab.com][10])\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary framework documentation:\n\n* FastAPI (PyPI metadata, versioning) — `https://pypi.org/project/fastapi/` ([PyPI][1])\n* FastAPI docs: Security “First Steps” (Authorization Bearer header conventions) — `https://fastapi.tiangolo.com/tutorial/security/first-steps/` ([FastAPI][11])\n* FastAPI reference: Dependencies (`Depends`, `Security`) — `https://fastapi.tiangolo.com/reference/dependencies/` ([FastAPI][7])\n* FastAPI reference: APIRouter (router-level dependencies) — `https://fastapi.tiangolo.com/reference/apirouter/` ([FastAPI][28])\n* FastAPI docs: WebSockets — `https://fastapi.tiangolo.com/advanced/websockets/` ([FastAPI][27])\n\nASGI/server stack documentation:\n\n* Starlette (PyPI, general capabilities) — `https://pypi.org/project/starlette/` ([PyPI][5])\n* Starlette docs: WebSockets — `https://starlette.dev/websockets/` ([Starlette][3])\n* Uvicorn (PyPI metadata) — `https://pypi.org/project/uvicorn/` ([PyPI][4])\n* Pydantic docs (v2.12.x) — `https://docs.pydantic.dev/latest/` ([Pydantic][29])\n\nSecurity standards and cheat sheets:\n\n* OWASP Cheat Sheet Series: Session Management — `https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][8])\n* OWASP Cheat Sheet Series: CSRF Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][2])\n* OWASP Cheat Sheet Series: XSS Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][16])\n* OWASP Cheat Sheet Series: Mass Assignment — `https://cheatsheetseries.owasp.org/cheatsheets/Mass_Assignment_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][14])\n* OWASP API Security Top 10 (2023) — `https://owasp.org/API-Security/editions/2023/en/0x11-t10/` ([OWASP Foundation][13])\n* OWASP Cheat Sheet Series: SQL Injection Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][21])\n* OWASP Cheat Sheet Series: OS Command Injection Defense — `https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][22])\n* OWASP Cheat Sheet Series: SSRF Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][23])\n* OWASP Cheat Sheet Series: File Upload — `https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][20])\n* OWASP Cheat Sheet Series: Unvalidated Redirects and Forwards — `https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][24])\n* OWASP Cheat Sheet Series: HTTP Security Response Headers — `https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][6])\n* OWASP Cheat Sheet Series: WebSocket Security — `https://cheatsheetseries.owasp.org/cheatsheets/WebSocket_Security_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][25])\n* OWASP WSTG: Testing for Server-Side Template Injection — `https://owasp.org/www-project-web-security-testing-guide/v41/4-Web_Application_Security_Testing/07-Input_Validation_Testing/18-Testing_for_Server_Side_Template_Injection` ([OWASP Foundation][17])\n* OWASP WSTG: Testing WebSockets — `https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/11-Client-side_Testing/10-Testing_WebSockets` ([OWASP Foundation][26])\n\nTemplate safety references:\n\n* Jinja: Sandbox — `https://jinja.palletsprojects.com/en/stable/sandbox/` ([jinja.palletsprojects.com][18])\n\nSelected supply-chain/advisory references (Starlette examples):\n\n* CVE-2023-29159 (StaticFiles path traversal; fixed 0.27.0) — `https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2023-29159/` ([advisories.gitlab.com][10])\n* CVE-2024-47874 (multipart/form-data DoS; fixed 0.40.0) — `https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2024-47874/` ([advisories.gitlab.com][9])\n* CVE-2025-62727 (FileResponse Range header DoS; fixed 0.49.1) — `https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2025-62727/` ([advisories.gitlab.com][19])\n\n[1]: https://pypi.org/project/fastapi/ \"https://pypi.org/project/fastapi/\"\n[2]: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html\"\n[3]: https://starlette.dev/websockets/?utm_source=chatgpt.com \"Websockets\"\n[4]: https://pypi.org/project/uvicorn/ \"https://pypi.org/project/uvicorn/\"\n[5]: https://pypi.org/project/starlette/ \"https://pypi.org/project/starlette/\"\n[6]: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html?utm_source=chatgpt.com \"HTTP Security Response Headers Cheat Sheet\"\n[7]: https://fastapi.tiangolo.com/reference/dependencies/?utm_source=chatgpt.com \"Dependencies - Depends() and Security() - FastAPI\"\n[8]: https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html\"\n[9]: https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2024-47874/ \"Starlette Denial of service (DoS) via multipart/form-data | GitLab Advisory Database\"\n[10]: https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2023-29159/ \"Starlette has Path Traversal vulnerability in StaticFiles | GitLab Advisory Database\"\n[11]: https://fastapi.tiangolo.com/tutorial/security/first-steps/?utm_source=chatgpt.com \"Security - First Steps - FastAPI\"\n[12]: https://fastapi.tiangolo.com/tutorial/response-model/ \"https://fastapi.tiangolo.com/tutorial/response-model/\"\n[13]: https://owasp.org/API-Security/editions/2023/en/0x11-t10/ \"https://owasp.org/API-Security/editions/2023/en/0x11-t10/\"\n[14]: https://cheatsheetseries.owasp.org/cheatsheets/Mass_Assignment_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Mass_Assignment_Cheat_Sheet.html\"\n[15]: https://fastapi.tiangolo.com/tutorial/extra-models/ \"https://fastapi.tiangolo.com/tutorial/extra-models/\"\n[16]: https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html\"\n[17]: https://owasp.org/www-project-web-security-testing-guide/v41/4-Web_Application_Security_Testing/07-Input_Validation_Testing/18-Testing_for_Server_Side_Template_Injection?utm_source=chatgpt.com \"Testing for Server Side Template Injection\"\n[18]: https://jinja.palletsprojects.com/en/stable/sandbox/?utm_source=chatgpt.com \"Sandbox — Jinja Documentation (3.1.x)\"\n[19]: https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2025-62727/ \"Starlette vulnerable to O(n^2) DoS via Range header merging in ``starlette.responses.FileResponse`` | GitLab Advisory Database\"\n[20]: https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html\"\n[21]: https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html\"\n[22]: https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html\"\n[23]: https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html\"\n[24]: https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html?utm_source=chatgpt.com \"Unvalidated Redirects and Forwards Cheat Sheet\"\n[25]: https://cheatsheetseries.owasp.org/cheatsheets/WebSocket_Security_Cheat_Sheet.html?utm_source=chatgpt.com \"WebSocket Security - OWASP Cheat Sheet Series\"\n[26]: https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/11-Client-side_Testing/10-Testing_WebSockets?utm_source=chatgpt.com \"WSTG - Latest | OWASP Foundation\"\n[27]: https://fastapi.tiangolo.com/advanced/websockets/?utm_source=chatgpt.com \"WebSockets - FastAPI\"\n[28]: https://fastapi.tiangolo.com/reference/apirouter/?utm_source=chatgpt.com \"APIRouter class - FastAPI\"\n[29]: https://docs.pydantic.dev/latest/ \"https://docs.pydantic.dev/latest/\"\n","core/skills/builtin/security-best-practices/references/python-flask-web-server-security.md":"# Flask (Python) Web Security Spec (Flask 3.1.x, Python 3.x)\n\nThis document is designed as a **security spec** that supports:\n1) **Secure-by-default code generation** for new Flask code.\n2) **Security review / vulnerability hunting** in existing Flask code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n--------------------------------------------------------------------\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n- MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session cookies, SECRET_KEY).\n- MUST NOT “fix” security by disabling protections (e.g., turning off CSRF, relaxing CORS, disabling escaping, disabling auth checks).\n- MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and configuration values that justify the claim.\n- MUST treat uncertainty honestly: if a protection might exist in infrastructure (reverse proxy, WAF, CDN), report it as “not visible in app code; verify at runtime/config”.\n\n--------------------------------------------------------------------\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\nWhen asked to write new Flask code or modify existing code:\n- MUST follow every **MUST** requirement in this spec.\n- SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n- MUST prefer safe-by-default APIs and proven libraries over custom security code.\n- MUST avoid introducing new risky sinks (template rendering from strings, shell execution, dynamic imports, unsafe redirects, serving user files as HTML, etc.).\n\n### 1.2 Passive review mode (always on while editing)\nWhile working anywhere in a Flask repo (even if the user did not ask for a security scan):\n- MUST “notice” violations of this spec in touched/nearby code.\n- SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n- MUST systematically search the codebase for violations of this spec.\n- MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n1) App entrypoints / deployment scripts / Dockerfiles / Procfiles.\n2) Flask configuration and environment handling.\n3) Auth + sessions + cookies.\n4) CSRF protections and state-changing routes.\n5) Template rendering and XSS/SSTI.\n6) File handling (uploads + downloads) and path traversal.\n7) Injection classes (SQL, command execution, unsafe deserialization).\n8) Outbound requests (SSRF).\n9) Redirect handling (open redirects).\n10) CORS and security headers.\n\n--------------------------------------------------------------------\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\nExamples include:\n- `request.args`, `request.form`, `request.values`\n- `request.get_json()`, `request.json`, `request.data`\n- `request.headers`, `request.cookies`\n- URL path parameters (e.g., `/user/<id>`)\n- Any data from external systems (webhooks, third-party APIs, message queues)\n- Any persisted user content (DB rows) that originated from users\n\n### 2.2 State-changing request\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook send), or initiate privileged actions.\n\n### 2.3 Required audit finding format\nFor each issue found, output:\n\n- Rule ID:\n- Severity: Critical / High / Medium / Low\n- Location: file path + function/route name + line(s)\n- Evidence: the exact code/config snippet\n- Impact: what could go wrong, who can exploit it\n- Fix: safe change (prefer minimal diff)\n- Mitigation: defense-in-depth if immediate fix is hard\n- False positive notes: what to verify if uncertain\n\n--------------------------------------------------------------------\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common Flask misconfigurations.\n\n### 3.1 App initialization pattern (SHOULD)\nSHOULD use an app factory and environment-based config so production config is not hard-coded.\n\nExample skeleton (illustrative; adjust to your project):\n- Load config from environment / secret store.\n- Fail closed if critical settings are missing in production.\n\nKey baseline config targets:\n- `SECRET_KEY` set and not committed\n- `SESSION_COOKIE_SECURE=True` (when HTTPS) IMPORTANT NOTE: Only set `Secure` in production environment when TLS is configured. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n- `SESSION_COOKIE_HTTPONLY=True`\n- `SESSION_COOKIE_SAMESITE='Lax'` (or `'Strict'` if compatible)\n- `TRUSTED_HOSTS` set in production\n- Security headers set (CSP, etc.) either in app or at the edge\n\n--------------------------------------------------------------------\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### FLASK-DEPLOY-001: Do not use Flask’s development server in production\nSeverity: High (if production)\n\nRequired:\n- MUST NOT deploy the built-in development server as the production server.\n- MUST run behind a production-grade WSGI server or managed platform (such as gunicorn)\n\nInsecure patterns:\n- `app.run(...)` in a production entrypoint.\n- Deployment docs/scripts that use `flask run` in production.\n\nDetection hints:\n- Search for `app.run(`, `flask run`, `--debug`, `FLASK_DEBUG`, `FLASK_ENV=development`.\n- Check Docker CMD/ENTRYPOINT, Procfile, systemd units, shell scripts.\n\nFix:\n- Use a production WSGI server (and keep Flask as the app object).\n- Ensure the dev server is only used for local development.\n\nNote:\n- These are often used in dev mode or local testing. This is allowed. Only flag if it is clear that it is being used as the production entrypoint\n\n---\n\n### FLASK-DEPLOY-002: Debug mode MUST be disabled in production\nSeverity: Critical\n\nRequired:\n- MUST NOT enable debug mode in production.\n- MUST treat the interactive debugger as equivalent to remote code execution if exposed.\n\nInsecure patterns:\n- `app.run(debug=True)`\n- `flask run --debug` in production.\n- `DEBUG=True` via env/config in production.\n\nDetection hints:\n- Look for `debug=True`, `FLASK_DEBUG=1`, `DEBUG = True`, `app.debug = True`.\n- Look for `TRAP_HTTP_EXCEPTIONS`/debugger settings enabled in non-test contexts.\n\nFix:\n- Ensure debug is only enabled in local dev/test.\n- Prefer environment-based toggles and safe defaults.\n\nNote:\n- These are often used in dev mode or local testing. This is allowed. Only flag if it is clear that it is being used as the production entrypoint\n\n---\n\n### FLASK-CONFIG-001: SECRET_KEY must be strong, secret, and rotated safely\nSeverity: High (Critical if missing in production with sessions or signing)\n\nRequired:\n- MUST set a strong random `SECRET_KEY` in production.\n- MUST keep `SECRET_KEY` out of source control and out of logs.\n- MAY rotate keys periodically; MAY use `SECRET_KEY_FALLBACKS` to support rotation without instantly invalidating existing sessions, then remove old keys after the rotation window. This likely is not needed for smaller applications but is good practice for larger applications. As this may complicate deployment, suggest that it be implemented rather than implementing it by default.\n\nInsecure patterns:\n- Missing `SECRET_KEY` in production.\n- Hard-coded `SECRET_KEY` in repo (including test keys accidentally used in prod).\n- Logging or printing `SECRET_KEY`.\n\nDetection hints:\n- Search for `SECRET_KEY =`, `app.secret_key =`, `SECRET_KEY_FALLBACKS =`.\n- Check `.env` files committed to repo.\n- Check config modules for constants.\n\nFix:\n- Load from secret manager or environment variable.\n- Add a rotation process:\n  - Set new `SECRET_KEY`\n  - Keep old key(s) temporarily in `SECRET_KEY_FALLBACKS`\n  - Remove old key(s) after the safe window.\n\nNotes:\n- If the application uses Flask sessions (cookie-based by default), `SECRET_KEY` is directly security-critical.\n\n---\n\n### FLASK-SESS-001: Session cookies must use secure attributes in production\nSeverity: Medium\n\nRequired (production, HTTPS):\n- MUST set `SESSION_COOKIE_SECURE=True` (cookies only over HTTPS). NOTE: Only set `Secure` in production environment when TLS is configured. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n- MUST ensure `SESSION_COOKIE_HTTPONLY=True` (protect from JS access).\n- SHOULD set `SESSION_COOKIE_SAMESITE='Lax'` (recommended) or `'Strict'` if compatible with UX.\n- SHOULD keep `SESSION_COOKIE_DOMAIN=None` unless you explicitly need subdomain-wide cookies.\n- If you need embedded/iframe third-party usage, MAY consider `SESSION_COOKIE_PARTITIONED=True` (requires HTTPS).\n\nInsecure patterns:\n- `SESSION_COOKIE_SECURE=False` in production.\n- `SESSION_COOKIE_HTTPONLY=False`.\n- `SESSION_COOKIE_SAMESITE=None` with cookie-authenticated state-changing endpoints (higher CSRF risk).\n\nDetection hints:\n- Inspect `app.config.update(...)` blocks and config classes.\n- Look for `set_cookie(..., secure=..., httponly=..., samesite=...)` usage on non-session cookies too.\n\nFix:\n- Set these config values explicitly in production config.\n\nNotes:\n- SameSite is defense-in-depth; do not treat it as a full replacement for CSRF tokens.\n\n---\n\n### FLASK-SESS-002: Sessions must be bounded and resistant to fixation/replay\nSeverity: Medium\n\nRequired:\n- SHOULD set a bounded session lifetime appropriate to the app.\n- SHOULD set `session.permanent = True` only when you intend persistent sessions, and set `PERMANENT_SESSION_LIFETIME` to a justified value.\n- SHOULD clear the session on login and privilege changes to reduce session fixation risk.\n- MUST NOT store sensitive secrets in the default Flask session cookie. The default session is signed, not encrypted.\n\nInsecure patterns:\n- Extremely long or unlimited lifetimes for privileged sessions.\n- No session clearing on login.\n- Storing secrets (passwords, access tokens, PII) directly in `session[...]` when using default cookie sessions.\n\nDetection hints:\n- Search for `PERMANENT_SESSION_LIFETIME`, `session.permanent`, `session[...] =`.\n- Identify whether server-side session storage is used; if not, assume default cookie sessions.\n\nFix:\n- Set appropriate lifetimes.\n- Clear/rotate session on login.\n- Store sensitive data server-side; store only identifiers in the session cookie.\n\n---\n\n### FLASK-CSRF-001: State-changing requests using cookie auth MUST be CSRF-protected\nSeverity: High\n\n- IMPORTANT NOTE: If cookies are not being used for auth (ie auth is via Authentication header or other passed token), then there is no CSRF risk.\n\nRequired:\n- MUST protect all state-changing endpoints (POST/PUT/PATCH/DELETE) that rely on cookies for authentication.\n- MAY use a well-tested CSRF library/integration (form framework or middleware) rather than rolling your own.\n- MAY use additional defenses (Origin/Referer checking, SameSite cookies, Fetch Metadata headers, custom headers for AJAX/API), but tokens remain the primary defense for cookie-authenticated apps.\nIf tokens are impractical, or for small applications:\n* MUST at a minimum require a custom header to be set and set the session cookie SESSION_COOKIE_SAMESITE=lax, as this is the strongest method besides requiring a form token, and may be much easier to implement.\n\nInsecure patterns:\n- Cookie-authenticated endpoints that change state with no CSRF protection.\n- Using GET for state-changing actions (amplifies CSRF risk).\n\nDetection hints:\n- Enumerate routes with methods other than GET and identify auth mechanism.\n- Look for CSRF integrations (e.g., Flask-WTF, global CSRF middleware). If absent, treat as suspicious.\n- Check JSON API endpoints too, not only HTML forms.\n\nFix:\n- Add CSRF protection to all state-changing requests.\n- If the app is a pure API and uses Authorization headers (bearer tokens) rather than cookies, document that choice and ensure cookies aren’t used for auth. If cookies are not used for auth, there is no CSRF risk.\n\nNotes:\n- XSS can defeat CSRF protections; CSRF defenses do not replace XSS prevention.\n\n---\n\n### FLASK-XSS-001: Prevent reflected/stored XSS in templates and HTML generation\nSeverity: High\n\nRequired:\n- MUST rely on Jinja auto-escaping for HTML templates.\n- MUST NOT mark untrusted content as safe:\n  - Avoid `Markup(...)` on user data.\n  - Avoid Jinja `|safe` on user-controlled content.\n- MUST quote HTML attributes containing Jinja expressions (`value=\"{{ x }}\"` not `value={{ x }}`).\n- MUST NOT serve uploaded HTML as active HTML; serve as download (`Content-Disposition: attachment`) or transform to a safe format. Note: This is only relevant if it is possible to upload document content such as html, js, css, etc. If it purely is image files, there is no concern.\n- SHOULD deploy a Content Security Policy (CSP) to mitigate XSS classes (including `javascript:` in `href`).\n\nInsecure patterns:\n- `Markup(request.args.get(...))`\n- Template filters: `{{ user_html|safe }}`\n- Unquoted attributes in templates\n- Serving user-uploaded content directly with `text/html` or inline rendering\n\nDetection hints:\n- Search for `Markup(` and investigate origin of the data.\n- Search template files for `|safe`, `|tojson` misuse, and unquoted attributes.\n- Review file-serving routes that might return user uploads without `as_attachment=True`. Note: This is only relevant if it is possible to upload document content such as html, js, css, etc. If it purely is image files, there is no concern.\n\nFix:\n- Remove unsafe marking; sanitize only when strictly necessary using a trusted HTML sanitizer.\n- Always quote attributes.\n- Add CSP and reduce inline scripts.\n\n---\n\n### FLASK-SSTI-001: Never render untrusted templates (Server-Side Template Injection)\nSeverity: Critical\n\nRequired:\n- MUST NOT render templates that contain user-controlled template syntax.\n- MUST treat `render_template_string` and `Environment.from_string(...).render(...)` as dangerous if the template string is influenced by untrusted input.\n- MUST NOT use use `.format()` on user controlled strings\n- If untrusted templates are absolutely required, treat it as a special high-risk design:\n  - MUST use a sandboxed templating approach and restrict capabilities.\n  - MUST keep Jinja updated and assume sandbox escapes are possible; isolate further.\n\nInsecure patterns:\n- `render_template_string(request.args[\"tmpl\"], ...)`\n- Storing user templates in DB and rendering them with the normal Jinja environment.\n- `request.args[\"tmpl\"].format(...)`\n\nDetection hints:\n- Grep for `render_template_string`, `from_string`, `.render(` with dynamic strings.\n- Trace the origin of the template string (DB, request, uploads, admin panels).\n\nFix:\n- Replace with safe templating alternatives that do not evaluate code (e.g., string.Template, str.replace).\n- If templates must be user-defined, use a sandbox plus strict allowlists and heavy isolation.\n\n---\n\n### FLASK-HEADERS-001: Set essential security headers (in app or at the edge)\nSeverity: Medium\n\nRequired (typical web app):\n- SHOULD set:\n  - CSP (`Content-Security-Policy`)\n  - `X-Content-Type-Options: nosniff`\n  - Clickjacking protection (`X-Frame-Options: SAMEORIGIN` and/or CSP `frame-ancestors`) (there may be cases where the user wants to iframe their site elsewhere. If that is the case, work with them to safely allow it)\n- SHOULD consider additional hardening headers depending on app (Referrer-Policy, Permissions-Policy).\n- MUST ensure cookies are set with secure attributes (see FLASK-SESS-001).\n\nNOTE: Security headers may be set via a proxy or other cloud provider. Check to see if there is evidence of that.\n\nInsecure patterns:\n- No security headers anywhere (app or edge).\n- CSP missing on apps that display untrusted content.\n\nDetection hints:\n- Search for `after_request` hooks, Flask-Talisman usage, reverse proxy config.\n- If not visible in app code, flag as “verify at edge”.\n\nFix:\n- Set headers centrally (middleware / after_request) or via reverse proxy/CDN.\n- Keep CSP realistic and compatible; avoid `unsafe-inline` where possible.\n\n---\n\n### FLASK-LIMITS-001: Request size and form parsing limits MUST be set appropriately\nSeverity: Low (Medium if file uploads / large bodies are possible)\n\nRequired:\n- SHOULD set and justify:\n  - `MAX_CONTENT_LENGTH` (global maximum request bytes)\n  - `MAX_FORM_MEMORY_SIZE` (max per non-file form field in multipart)\n  - `MAX_FORM_PARTS` (max number of multipart fields)\n- MUST enforce additional limits at the reverse proxy / WSGI / platform level where possible.\n\nInsecure patterns:\n- Unlimited request body sizes when handling uploads or user content.\n- Accepting arbitrarily large multipart forms or many fields.\n\nDetection hints:\n- Inspect Flask config for these keys.\n- Inspect upload routes and APIs that accept large JSON.\n\nFix:\n- Set conservative defaults, override per-route only when needed.\n- Ensure large uploads use dedicated upload mechanisms.\n\n---\n\n### FLASK-HOST-001: Host header must be validated in production\nSeverity: Low (depends on app’s use of external URLs)\n\nRequired:\n- MUST set `TRUSTED_HOSTS` in production to restrict accepted Host values.\n- MUST NOT rely on `SERVER_NAME` as a host restriction mechanism.\n\nInsecure patterns:\n- `TRUSTED_HOSTS` unset in production.\n- Code that generates external URLs for emails/password resets without host validation.\n\nDetection hints:\n- Find `TRUSTED_HOSTS` config usage.\n- Find `url_for(..., _external=True)` and check how host is determined.\n\nFix:\n- Set `TRUSTED_HOSTS` to your expected domains (and required subdomains).\n- Ensure external URL generation uses trusted host/scheme.\n\n---\n\n### FLASK-PROXY-001: Reverse proxy trust must be configured correctly\nSeverity: Medium (High if relying on IPs for auth)\n\nRequired:\n- If behind a reverse proxy, MUST configure Flask/Werkzeug to trust forwarded headers only from the intended proxy.\n- MUST NOT blindly trust `X-Forwarded-*` headers from the open internet.\n\nInsecure patterns:\n- `ProxyFix` applied with overly broad trust settings, or applied without understanding how many proxies are in front.\n- Relying on forwarded headers for scheme/host without validation.\n\nDetection hints:\n- Search for `ProxyFix`.\n- Search for usage of `request.remote_addr`, `request.scheme`, `request.host` in security-sensitive logic.\n\nFix:\n- Configure `ProxyFix` (or platform-specific settings) with correct hop counts.\n- Keep `TRUSTED_HOSTS` in place even behind proxies.\n\n---\n\n### FLASK-PATH-001: Prevent path traversal and unsafe file serving\nSeverity: High\n\nRequired:\n- MUST NOT pass user-controlled file paths to `send_file` or to direct file I/O.\n- MUST use safe file serving patterns:\n  - `send_from_directory` for user-specified paths under a trusted base directory\n  - `safe_join` for joining a trusted base directory with untrusted path components\n  - `secure_filename` for uploaded filenames (and still generate your own unique storage name)\n- MUST ensure user uploads are not served as executable/active content (especially HTML).\n- SHOULD in general use `safe_join` over `os.path.join` for almost any filesystem path computations.\n\nInsecure patterns:\n- `send_file(request.args[\"path\"])`\n- `open(os.path.join(base_dir, user_path))` where `user_path` is untrusted\n- Serving uploads from within a static web root without restrictions\n\nDetection hints:\n- Search for `send_file(`, `open(`, `os.path.join(`, `pathlib.Path(...)/...` in file routes.\n- Identify where filenames come from (request args, DB, headers).\n\nFix:\n- Serve only from a non-user-controlled directory base.\n- Store uploads outside static roots; serve through controlled routes.\n- Always validate and normalize file identifiers.\n\nNote: `safe_join` is imported from `werkzeug.security`\n\n---\n\n### FLASK-UPLOAD-001: File uploads must be validated, stored safely, and served safely\nSeverity: High\n\nRequired:\n- MUST enforce upload size limits (app + edge).\n- MUST validate file type using allowlists and content checks (not only extension).\n- MUST store uploads outside executable/static roots when possible.\n- SHOULD generate server-side filenames (random IDs) and avoid trusting original names.\n- MUST serve potentially active formats safely (download attachment) unless explicitly intended.\n\nInsecure patterns:\n- Accepting arbitrary file types and serving them back inline.\n- Using user-supplied filename as storage path.\n- Missing size/type validation.\n\nDetection hints:\n- Look for `request.files[...]` handlers.\n- Check for `secure_filename` usage (and whether it’s combined with uniqueness).\n- Check where files are stored and how they are served.\n\nFix:\n- Implement allowlist validation + safe storage + safe serving.\n- Add scanning / quarantine if applicable.\n\n---\n\n### FLASK-INJECT-001: Prevent SQL injection (use parameterized queries / ORM)\nSeverity: High\n\nRequired:\n- MUST use parameterized queries or an ORM that parameterizes under the hood.\n- MUST NOT build SQL by string concatenation / f-strings with untrusted input.\n\nInsecure patterns:\n- `f\"SELECT ... WHERE id={request.args['id']}\"`\n- `\"... WHERE name = '%s'\" % user_input`\n\nDetection hints:\n- Grep for `SELECT`, `INSERT`, `UPDATE`, `DELETE` strings in Python code.\n- Track untrusted data into DB execute calls.\n\nFix:\n- Replace with parameterized queries or ORM query APIs.\n- Validate types (e.g., int IDs) before querying.\n\n---\n\n### FLASK-INJECT-002: Prevent OS command injection\nSeverity: Critical to High (depends on exposure)\n\nRequired:\n- MUST avoid executing shell commands with untrusted input.\n- If subprocess is necessary:\n  - MUST pass args as a list (not a string)\n  - MUST NOT use `shell=True` with attacker-influenced strings\n  - SHOULD use strict allowlists for any variable component\n- If possible, use pure python or a python library rather than using a subprocess or system command\n- Do not assume that arguments to commands will be inherently safe even in `shell=False`. Commands may incorrectly process these arguments as command line flags or other trusted values.\n\nInsecure patterns:\n- `os.system(user_input)`\n- `subprocess.run(f\"cmd {user}\", shell=True)`\n- Passing user strings into `bash -c`, `sh -c`, PowerShell, etc.\n\nDetection hints:\n- Search for `os.system`, `subprocess`, `Popen`, `shell=True`.\n- Trace data from request/DB into these calls.\n\nFix:\n- Use library APIs instead of shell commands.\n- If unavoidable, hard-code the command and allowlist validated parameters. If supported by the subcommand, try to keep user values after `--` to prevent them being processed as command line flags.\n\n---\n\n### FLASK-SSRF-001: Prevent server-side request forgery (SSRF) in outbound HTTP\nSeverity: Medium\n\n- Note: For small stand alone projects this is less important. It is most important when deploying into an LAN or with other services listening on the same server.\n\nRequired:\n- MUST treat outbound requests to user-provided URLs as high risk.\n- SHOULD validate and restrict destinations (allowlist hosts/domains) for any user-influenced URL fetch.\n- SHOULD block access to:\n  - localhost / private IP ranges / link-local addresses\n  - cloud metadata endpoints\n- MUST NOT allow non http/https protocols (ie file: etc)\n- SHOULD set timeouts and restrict redirects.\n\n\n\nInsecure patterns:\n- `requests.get(request.args[\"url\"])`\n- Webhooks/preview/fetch endpoints that accept arbitrary URLs.\n\nDetection hints:\n- Search for `requests.get/post`, `httpx`, `urllib`, `aiohttp` usage with untrusted URL sources.\n- Identify URL fetch features (preview, import, webhook tester).\n\nFix:\n- Ensure URLs are http or https (disallow file: or other protocols)\n- Enforce allowlists and network egress controls.\n- Add strict parsing and IP resolution checks; set timeouts; disable redirects if not needed.\n\n---\n\n### FLASK-REDIRECT-001: Prevent open redirects\nSeverity: Low\n\nRequired:\n- MUST validate redirect targets derived from untrusted input (e.g., `next`, `redirect`, `return_to`).\n- SHOULD use allowlists of internal paths or known domains.\n- SHOULD prefer redirecting only to same-site relative paths.\n\nInsecure patterns:\n- `redirect(request.args.get(\"next\"))` with no validation.\n\nDetection hints:\n- Search for `redirect(` and examine where `location` comes from.\n\nFix:\n- Only allow relative paths or allowlisted domains.\n- Fall back to a safe default if validation fails.\n\n---\n\n### FLASK-HTTP-001: Use HTTP methods safely; do not change state via GET; avoid secrets in URLs\nSeverity: Medium\n\nRequired:\n- MUST NOT perform state-changing actions over GET.\n- MUST NOT put secrets in URLs (query strings are commonly logged and leaked via referrers).\n- SHOULD require POST/PUT/PATCH/DELETE for state change and apply CSRF protections when cookie-authenticated.\n\nInsecure patterns:\n- `/delete?id=...` implemented as GET\n- Password reset tokens or API keys in query params\n\nDetection hints:\n- Enumerate GET routes and inspect whether they mutate state.\n- Look for URL parameters named `token`, `key`, `secret`, `password`, etc.\n\nFix:\n- Move state changes to non-GET methods.\n- Move sensitive values to secure channels (POST bodies, headers) and protect them.\n\n---\n\n### FLASK-CORS-001: CORS must be explicit and least-privilege\nSeverity: Medium (High if misconfigured with credentials)\n\nRequired:\n- If CORS is not needed, MUST keep it disabled.\n- If CORS is needed:\n  - MUST allowlist trusted origins (do not reflect arbitrary origins).\n  - MUST be careful with credentialed requests; do not combine broad origins with cookies.\n  - SHOULD restrict allowed methods and headers.\n\nInsecure patterns:\n- `Access-Control-Allow-Origin: *` paired with credentialed cookies or overly broad access.\n- Reflecting `Origin` without validation.\n- `flask_cors.CORS(app)` with permissive defaults.\n\nDetection hints:\n- Search for `flask_cors`, `CORS(`, `Access-Control-Allow-Origin`.\n- Check for `supports_credentials=True` and wildcard origins.\n\nFix:\n- Use a strict origin allowlist and minimal methods/headers.\n- Ensure cookie-authenticated endpoints are not exposed cross-origin unless necessary.\n\n---\n\n### FLASK-SUPPLY-001: Dependency and patch hygiene (focus on security-relevant deps)\nSeverity: Low\n\nRequired:\n- SHOULD pin and regularly update security-critical dependencies (Flask, Werkzeug, Jinja2, itsdangerous).\n- MUST respond to known security advisories promptly.\n\nAudit focus example:\n- If running on Windows and using file serving with untrusted paths, ensure Werkzeug’s `safe_join` behavior is not vulnerable to Windows device-name edge cases.\n\nDetection hints:\n- Check `requirements.txt`, lockfiles, and runtime environments.\n- Identify where security helpers are used (safe_join, send_from_directory).\n\nFix:\n- Upgrade to patched versions and add regression tests for the impacted behavior.\n\n--------------------------------------------------------------------\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n- Dev server / debug:\n  - `app.run(`, `flask run`, `--debug`, `DEBUG=True`, `FLASK_DEBUG`\n- Secrets:\n  - `SECRET_KEY`, `secret_key`, `.env` committed, `print(config)`\n- Cookies / sessions:\n  - `SESSION_COOKIE_SECURE`, `SESSION_COOKIE_HTTPONLY`, `SESSION_COOKIE_SAMESITE`\n  - `session[...] =` with sensitive values\n- CSRF:\n  - POST/PUT/PATCH/DELETE handlers without CSRF checks in cookie-authenticated apps\n- XSS/SSTI:\n  - `Markup(`, `|safe`, unquoted attributes, `render_template_string`\n- Files:\n  - `send_file(` with user-controlled path; `open(` on user path; `os.path.join` with untrusted\n  - upload handlers using user filename for path\n- Injection:\n  - SQL strings + string formatting into `.execute(...)`\n  - `subprocess.*`, `shell=True`, `os.system`\n- SSRF:\n  - `requests.get/post` or `httpx` with URL from request/DB\n- Redirect:\n  - `redirect(request.args.get(\"next\"))`\n- CORS:\n  - `flask_cors.CORS` permissive configs; wildcard origins with credentials\n\nAlways try to confirm:\n- data origin (untrusted vs trusted)\n- sink type (template/SQL/subprocess/files/redirect/http)\n- protective controls present (validation, allowlists, middleware)\n\n--------------------------------------------------------------------\n\n## 6) Sources (accessed 2026-01-26)\n\nPrimary framework documentation:\n- Flask Docs: Deploying to Production — https://flask.palletsprojects.com/en/stable/deploying/\n- Flask Docs: Debugging Application Errors — https://flask.palletsprojects.com/en/stable/debugging/\n- Flask Docs: Configuration Handling — https://flask.palletsprojects.com/en/stable/config/\n- Flask Docs: Security Considerations — https://flask.palletsprojects.com/en/stable/web-security/\n- Flask Docs: Tell Flask it is Behind a Proxy — https://flask.palletsprojects.com/en/stable/deploying/proxy_fix/\n- Flask API Docs: Sessions — https://flask.palletsprojects.com/en/stable/api/#sessions\n\nWerkzeug documentation & advisories:\n- Werkzeug Docs: Utilities (send_file / send_from_directory / safe_join / secure_filename / password hashing) — https://werkzeug.palletsprojects.com/en/stable/utils/\n- GitHub Advisory: CVE-2025-66221 (Werkzeug safe_join Windows device names) — https://github.com/advisories/GHSA-hgf8-39gv-g3f2\n\nOWASP Cheat Sheet Series:\n- Session Management — https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html\n- CSRF Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html\n- XSS Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html\n- Input Validation — https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html\n- SQL Injection Prevention — https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html\n- Injection Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Injection_Prevention_Cheat_Sheet.html\n- OS Command Injection Defense — https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html\n- SSRF Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html\n- File Upload — https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html\n- Unvalidated Redirects — https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html\n- HTTP Headers — https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html\n\nTemplate safety references:\n- Jinja: Sandbox (rendering untrusted templates) — https://jinja.palletsprojects.com/en/stable/sandbox/\n- OWASP WSTG: Testing for Server-Side Template Injection — https://owasp.org/www-project-web-security-testing-guide/v41/4-Web_Application_Security_Testing/07-Input_Validation_Testing/18-Testing_for_Server_Side_Template_Injection\n- PortSwigger Web Security Academy: Server-side template injection — https://portswigger.net/web-security/server-side-template-injection\n\nHTTP semantics:\n- RFC 9110: HTTP Semantics (safe methods) — https://www.rfc-editor.org/rfc/rfc9110\n","core/skills/builtin/security-ownership-map/SKILL.md":"---\nname: \"security-ownership-map\"\ndescription: \"Analyze git repositories to build a security ownership topology (people-to-file), compute bus factor and sensitive-code ownership, and export CSV/JSON for graph databases and visualization. Trigger only when the user explicitly wants a security-oriented ownership or bus-factor analysis grounded in git history (for example: orphaned sensitive code, security maintainers, CODEOWNERS reality checks for risk, sensitive hotspots, or ownership clusters). Do not trigger for general maintainer lists or non-security ownership questions.\"\n---\n\n# Security Ownership Map\n\n## Overview\n\nBuild a bipartite graph of people and files from git history, then compute ownership risk and export graph artifacts for Neo4j/Gephi. Also build a file co-change graph (Jaccard similarity on shared commits) to cluster files by how they move together while ignoring large, noisy commits.\n\n## Requirements\n\n- Python 3\n- `networkx` (required; community detection is enabled by default)\n\nInstall with:\n\n```bash\npip install networkx\n```\n\n## Workflow\n\n1. Scope the repo and time window (optional `--since/--until`).\n2. Decide sensitivity rules (use defaults or provide a CSV config).\n3. Build the ownership map with `scripts/run_ownership_map.py` (co-change graph is on by default; use `--cochange-max-files` to ignore supernode commits).\n4. Communities are computed by default; graphml output is optional (`--graphml`).\n5. Query the outputs with `scripts/query_ownership.py` for bounded JSON slices.\n6. Persist and visualize (see `references/neo4j-import.md`).\n\nBy default, the co-change graph ignores common “glue” files (lockfiles, `.github/*`, editor config) so clusters reflect actual code movement instead of shared infra edits. Override with `--cochange-exclude` or `--no-default-cochange-excludes`. Dependabot commits are excluded by default; override with `--no-default-author-excludes` or add patterns via `--author-exclude-regex`.\n\nIf you want to exclude Linux build glue like `Kbuild` from co-change clustering, pass:\n\n```bash\npython skills/skills/security-ownership-map/scripts/run_ownership_map.py \\\n  --repo /path/to/linux \\\n  --out ownership-map-out \\\n  --cochange-exclude \"**/Kbuild\"\n```\n\n## Quick start\n\nRun from the repo root:\n\n```bash\npython skills/skills/security-ownership-map/scripts/run_ownership_map.py \\\n  --repo . \\\n  --out ownership-map-out \\\n  --since \"12 months ago\" \\\n  --emit-commits\n```\n\nDefaults: author identity, author date, and merge commits excluded. Use `--identity committer`, `--date-field committer`, or `--include-merges` if needed.\n\nExample (override co-change excludes):\n\n```bash\npython skills/skills/security-ownership-map/scripts/run_ownership_map.py \\\n  --repo . \\\n  --out ownership-map-out \\\n  --cochange-exclude \"**/Cargo.lock\" \\\n  --cochange-exclude \"**/.github/**\" \\\n  --no-default-cochange-excludes\n```\n\nCommunities are computed by default. To disable:\n\n```bash\npython skills/skills/security-ownership-map/scripts/run_ownership_map.py \\\n  --repo . \\\n  --out ownership-map-out \\\n  --no-communities\n```\n\n## Sensitivity rules\n\nBy default, the script flags common auth/crypto/secret paths. Override by providing a CSV file:\n\n```\n# pattern,tag,weight\n**/auth/**,auth,1.0\n**/crypto/**,crypto,1.0\n**/*.pem,secrets,1.0\n```\n\nUse it with `--sensitive-config path/to/sensitive.csv`.\n\n## Output artifacts\n\n`ownership-map-out/` contains:\n\n- `people.csv` (nodes: people)\n- `files.csv` (nodes: files)\n- `edges.csv` (edges: touches)\n- `cochange_edges.csv` (file-to-file co-change edges with Jaccard weight; omitted with `--no-cochange`)\n- `summary.json` (security ownership findings)\n- `commits.jsonl` (optional, if `--emit-commits`)\n- `communities.json` (computed by default from co-change edges when available; includes `maintainers` per community; disable with `--no-communities`)\n- `cochange.graph.json` (NetworkX node-link JSON with `community_id` + `community_maintainers`; falls back to `ownership.graph.json` if no co-change edges)\n- `ownership.graphml` / `cochange.graphml` (optional, if `--graphml`)\n\n`people.csv` includes timezone detection based on author commit offsets: `primary_tz_offset`, `primary_tz_minutes`, and `timezone_offsets`.\n\n## LLM query helper\n\nUse `scripts/query_ownership.py` to return small, JSON-bounded slices without loading the full graph into context.\n\nExamples:\n\n```bash\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out people --limit 10\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out files --tag auth --bus-factor-max 1\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out person --person alice@corp --limit 10\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out file --file crypto/tls\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out cochange --file crypto/tls --limit 10\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out summary --section orphaned_sensitive_code\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out community --id 3\n```\n\nUse `--community-top-owners 5` (default) to control how many maintainers are stored per community.\n\n## Basic security queries\n\nRun these to answer common security ownership questions with bounded output:\n\n```bash\n# Orphaned sensitive code (stale + low bus factor)\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out summary --section orphaned_sensitive_code\n\n# Hidden owners for sensitive tags\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out summary --section hidden_owners\n\n# Sensitive hotspots with low bus factor\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out summary --section bus_factor_hotspots\n\n# Auth/crypto files with bus factor <= 1\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out files --tag auth --bus-factor-max 1\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out files --tag crypto --bus-factor-max 1\n\n# Who is touching sensitive code the most\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out people --sort sensitive_touches --limit 10\n\n# Co-change neighbors (cluster hints for ownership drift)\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out cochange --file path/to/file --min-jaccard 0.05 --limit 20\n\n# Community maintainers (for a cluster)\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out community --id 3\n\n# Monthly maintainers for the community containing a file\npython skills/skills/security-ownership-map/scripts/community_maintainers.py \\\n  --data-dir ownership-map-out \\\n  --file network/card.c \\\n  --since 2025-01-01 \\\n  --top 5\n\n# Quarterly buckets instead of monthly\npython skills/skills/security-ownership-map/scripts/community_maintainers.py \\\n  --data-dir ownership-map-out \\\n  --file network/card.c \\\n  --since 2025-01-01 \\\n  --bucket quarter \\\n  --top 5\n```\n\nNotes:\n- Touches default to one authored commit (not per-file). Use `--touch-mode file` to count per-file touches.\n- Use `--window-days 90` or `--weight recency --half-life-days 180` to smooth churn.\n- Filter bots with `--ignore-author-regex '(bot|dependabot)'`.\n- Use `--min-share 0.1` to show stable maintainers only.\n- Use `--bucket quarter` for calendar quarter groupings.\n- Use `--identity committer` or `--date-field committer` to switch from author attribution.\n- Use `--include-merges` to include merge commits (excluded by default).\n\n### Summary format (default)\n\nUse this structure, add fields if needed:\n\n```json\n{\n  \"orphaned_sensitive_code\": [\n    {\n      \"path\": \"crypto/tls/handshake.rs\",\n      \"last_security_touch\": \"2023-03-12T18:10:04+00:00\",\n      \"bus_factor\": 1\n    }\n  ],\n  \"hidden_owners\": [\n    {\n      \"person\": \"alice@corp\",\n      \"controls\": \"63% of auth code\"\n    }\n  ]\n}\n```\n\n## Graph persistence\n\nUse `references/neo4j-import.md` when you need to load the CSVs into Neo4j. It includes constraints, import Cypher, and visualization tips.\n\n## Notes\n\n- `bus_factor_hotspots` in `summary.json` lists sensitive files with low bus factor; `orphaned_sensitive_code` is the stale subset.\n- If `git log` is too large, narrow with `--since` or `--until`.\n- Compare `summary.json` against CODEOWNERS to highlight ownership drift.\n","core/skills/builtin/security-ownership-map/agents/openai.yaml":"interface:\n  display_name: \"Security Ownership Map\"\n  short_description: \"Map maintainers, bus factor, and sensitive code ownership\"\n  default_prompt: \"Build a security ownership map for this repository and identify bus-factor risks in sensitive code.\"\n","core/skills/builtin/security-ownership-map/references/neo4j-import.md":"# Neo4j Import Notes\n\nUse these steps when persisting the ownership graph to Neo4j.\n\n## Quick import (LOAD CSV)\n\n1. Copy `people.csv`, `files.csv`, and `edges.csv` into the Neo4j import directory.\n2. Run the following Cypher from Neo4j Browser or `cypher-shell`:\n\n```cypher\nCREATE CONSTRAINT person_id IF NOT EXISTS FOR (p:Person) REQUIRE p.id IS UNIQUE;\nCREATE CONSTRAINT file_id IF NOT EXISTS FOR (f:File) REQUIRE f.id IS UNIQUE;\n\nLOAD CSV WITH HEADERS FROM 'file:///people.csv' AS row\nMERGE (p:Person {id: row.person_id})\nSET p.name = row.name,\n    p.email = row.email,\n    p.first_seen = row.first_seen,\n    p.last_seen = row.last_seen,\n    p.commit_count = toInteger(row.commit_count),\n    p.touches = toInteger(row.touches),\n    p.sensitive_touches = toFloat(row.sensitive_touches),\n    p.primary_tz_offset = CASE row.primary_tz_offset WHEN '' THEN null ELSE row.primary_tz_offset END,\n    p.primary_tz_minutes = CASE row.primary_tz_minutes WHEN '' THEN null ELSE toInteger(row.primary_tz_minutes) END,\n    p.timezone_offsets = CASE row.timezone_offsets WHEN '' THEN null ELSE row.timezone_offsets END;\n\nLOAD CSV WITH HEADERS FROM 'file:///files.csv' AS row\nMERGE (f:File {id: row.file_id})\nSET f.path = row.path,\n    f.first_seen = row.first_seen,\n    f.last_seen = row.last_seen,\n    f.commit_count = toInteger(row.commit_count),\n    f.touches = toInteger(row.touches),\n    f.bus_factor = toInteger(row.bus_factor),\n    f.sensitivity_score = toFloat(row.sensitivity_score),\n    f.sensitivity_tags = row.sensitivity_tags;\n\nLOAD CSV WITH HEADERS FROM 'file:///edges.csv' AS row\nMATCH (p:Person {id: row.person_id})\nMATCH (f:File {id: row.file_id})\nMERGE (p)-[r:TOUCHES]->(f)\nSET r.touches = toInteger(row.touches),\n    r.recency_weight = toFloat(row.recency_weight),\n    r.first_seen = row.first_seen,\n    r.last_seen = row.last_seen,\n    r.sensitive_weight = toFloat(row.sensitive_weight);\n\nLOAD CSV WITH HEADERS FROM 'file:///cochange_edges.csv' AS row\nMATCH (f1:File {id: row.file_a})\nMATCH (f2:File {id: row.file_b})\nMERGE (f1)-[r:COCHANGES]->(f2)\nSET r.cochange_count = toInteger(row.cochange_count),\n    r.jaccard = toFloat(row.jaccard);\n```\n\n## Visualization tips\n\n- Use Neo4j Bloom or Browser with `MATCH (p:Person)-[r:TOUCHES]->(f:File) RETURN p,r,f`.\n- Filter by `f.sensitivity_score > 0` to highlight security-relevant clusters.\n- For Gephi, import `edges.csv` as edges and `files.csv` / `people.csv` as nodes.\n","core/skills/builtin/security-threat-model/SKILL.md":"---\nname: \"security-threat-model\"\ndescription: \"Repository-grounded threat modeling that enumerates trust boundaries, assets, attacker capabilities, abuse paths, and mitigations, and writes a concise Markdown threat model. Trigger only when the user explicitly asks to threat model a codebase or path, enumerate threats/abuse paths, or perform AppSec threat modeling. Do not trigger for general architecture summaries, code review, or non-security design work.\"\n---\n\n# Threat Model Source Code Repo\n\nDeliver an actionable AppSec-grade threat model that is specific to the repository or a project path, not a generic checklist. Anchor every architectural claim to evidence in the repo and keep assumptions explicit. Prioritizing realistic attacker goals and concrete impacts over generic checklists.\n\n## Quick start\n\n1) Collect (or infer) inputs:\n- Repo root path and any in-scope paths.\n- Intended usage, deployment model, internet exposure, and auth expectations (if known).\n- Any existing repository summary or architecture spec.\n- Use prompts in `references/prompt-template.md` to generate a repository summary.\n- Follow the required output contract in `references/prompt-template.md`. Use it verbatim when possible.\n\n## Workflow\n\n### 1) Scope and extract the system model\n- Identify primary components, data stores, and external integrations from the repo summary.\n- Identify how the system runs (server, CLI, library, worker) and its entrypoints.\n- Separate runtime behavior from CI/build/dev tooling and from tests/examples.\n- Map the in-scope locations to those components and exclude out-of-scope items explicitly.\n- Do not claim components, flows, or controls without evidence.\n\n### 2) Derive boundaries, assets, and entry points\n- Enumerate trust boundaries as concrete edges between components, noting protocol, auth, encryption, validation, and rate limiting.\n- List assets that drive risk (data, credentials, models, config, compute resources, audit logs).\n- Identify entry points (endpoints, upload surfaces, parsers/decoders, job triggers, admin tooling, logging/error sinks).\n\n### 3) Calibrate assets and attacker capabilities\n- List the assets that drive risk (credentials, PII, integrity-critical state, availability-critical components, build artifacts).\n- Describe realistic attacker capabilities based on exposure and intended usage.\n- Explicitly note non-capabilities to avoid inflated severity.\n\n\n### 4) Enumerate threats as abuse paths\n- Prefer attacker goals that map to assets and boundaries (exfiltration, privilege escalation, integrity compromise, denial of service).\n- Classify each threat and tie it to impacted assets.\n- Keep the number of threats small but high quality.\n\n### 5) Prioritize with explicit likelihood and impact reasoning\n- Use qualitative likelihood and impact (low/medium/high) with short justifications.\n- Set overall priority (critical/high/medium/low) using likelihood x impact, adjusted for existing controls.\n- State which assumptions most influence the ranking.\n\n### 6) Validate service context and assumptions with the user\n- Summarize key assumptions that materially affect threat ranking or scope, then ask the user to confirm or correct them.\n- Ask 1–3 targeted questions to resolve missing context (service owner and environment, scale/users, deployment model, authn/authz, internet exposure, data sensitivity, multi-tenancy).\n- Pause and wait for user feedback before producing the final report.\n- If the user declines or can’t answer, state which assumptions remain and how they influence priority.\n\n### 7) Recommend mitigations and focus paths\n- Distinguish existing mitigations (with evidence) from recommended mitigations.\n- Tie mitigations to concrete locations (component, boundary, or entry point) and control types (authZ checks, input validation, schema enforcement, sandboxing, rate limits, secrets isolation, audit logging).\n- Prefer specific implementation hints over generic advice (e.g., \"enforce schema at gateway for upload payloads\" vs \"validate inputs\").\n- Base recommendations on validated user context; if assumptions remain unresolved, mark recommendations as conditional.\n\n### 8) Run a quality check before finalizing\n- Confirm all discovered entrypoints are covered.\n- Confirm each trust boundary is represented in threats.\n- Confirm runtime vs CI/dev separation.\n- Confirm user clarifications (or explicit non-responses) are reflected.\n- Confirm assumptions and open questions are explicit.\n- Confirm that the format of the report matches closely the required output format defined in prompt template: `references/prompt-template.md`\n- Write the final Markdown to a file named `<repo-or-dir-name>-threat-model.md` (use the basename of the repo root, or the in-scope directory if you were asked to model a subpath).\n\n\n## Risk prioritization guidance (illustrative, not exhaustive)\n- High: pre-auth RCE, auth bypass, cross-tenant access, sensitive data exfiltration, key or token theft, model or config integrity compromise, sandbox escape.\n- Medium: targeted DoS of critical components, partial data exposure, rate-limit bypass with measurable impact, log/metrics poisoning that affects detection.\n- Low: low-sensitivity info leaks, noisy DoS with easy mitigation, issues requiring unlikely preconditions.\n\n## References\n\n- Output contract and full prompt template: `references/prompt-template.md`\n- Optional controls/asset list: `references/security-controls-and-assets.md`\n\nOnly load the reference files you need. Keep the final result concise, grounded, and reviewable.\n","core/skills/builtin/security-threat-model/agents/openai.yaml":"interface:\n  display_name: \"Security Threat Model\"\n  short_description: \"Repo-grounded threat modeling and abuse-path analysis\"\n  default_prompt: \"Create a repository-grounded threat model for this codebase with prioritized abuse paths and mitigations.\"\n","core/skills/builtin/security-threat-model/references/prompt-template.md":"# Threat Modeling Prompt Template for LLMs\n\nThis reference provides a disciplined, repo-grounded prompt that produces AppSec-usable threat models. Use it when you need a reliable output contract and a consistent process to assemble the threat model output\n\n## System prompt\n\nUse this as a stable system prompt:\n\n````text\nYou are a senior application security engineer producing a threat model that will be read by other AppSec engineers.\n\nPrimary objective:\n- Generate a threat model that is specific to THIS repository and its real-world usage.\n- Prefer concrete, evidence-backed findings over generic vulnerability checklists.\n\nEvidence and grounding rules:\n- Do not invent components, data stores, endpoints, flows, or controls.\n- Every architectural claim must be backed by at least one \"Evidence anchor\" referencing a repo path\n  (and a symbol name, config key, or a short quoted snippet if available).\n- If information is missing, state assumptions explicitly and list the open questions needed to validate them.\n\nSecurity hygiene:\n- Never output secrets. If you encounter tokens/keys/passwords, redact them and only describe their presence and location.\n\nThreat modeling approach:\n- Model the system using data flows and trust boundaries.\n- Enumerate threats and produce attack goals and abuse paths\n- Prioritize threats using explicit likelihood and impact reasoning (qualitative is acceptable: low/medium/high).\n\nScope discipline:\n- Clearly separate: production/runtime behavior vs CI/build/dev tooling vs tests/examples.\n- Clearly separate attacker-controlled inputs vs operator-controlled inputs vs developer-controlled inputs.\n- If a vulnerability class requires attacker control that likely does not exist for this repo's real usage, say so and downgrade severity.\n\nCommunication quality:\n- Write for AppSec engineers: concise but specific.\n- Use precise terminology. Include mitigations and residual risks.\n- Avoid restating large blocks of README/spec; summarize and point to evidence.\n\nDiagram requirements:\n- Produce a single compact Mermaid flowchart showing primary components and trust boundaries.\n- Mermaid must render cleanly. Use a conservative subset:\n  - Use `flowchart TD` or `flowchart LR` and only `-->` arrows.\n  - Use simple node IDs (letters/numbers/underscores only) and quoted labels (e.g., `A[\"Label\"]`); avoid `A(Label)` shape syntax.\n  - Do not use Mermaid `title` lines or `style` directives.\n  - Keep edge labels to plain words/spaces only via `-->|label|`; avoid `{}`, `[]`, `()`, or quotes in edge labels (if needed, drop the label).\n  - Keep node labels short and readable: do not include file paths, URLs, or socket paths (put those details in prose outside the diagram).\n- Wrap the diagram in a Markdown fenced block:\n  ```mermaid\n  <mermaid syntax here>\n  ```\n````\n\n## Repository summary prompt\n\n```\nWe have a codebase located at {repo_directory/path}, currently on branch {branch_name}.\n\nPlease produce a security-oriented summary of the repository (or the specified sub-path) with the goal of helping a follow-on security engineer quickly understand the system well enough to build an initial threat model and investigate potential security hypotheses.\n\nObjectives\n1.\tProject overview\n\t•\tIdentify the primary programming languages, frameworks, and build system.\n\t•\tSummarize the project’s core purpose and high-level architecture.\n\t•\tDescribe major components, services, or modules and how they interact.\n2.\tSecurity posture and entry points\n\t•\tIdentify likely user entry points and trust boundaries.\n\t•\tDescribe existing security layers (e.g., authentication, authorization, validation, sandboxing, isolation, privilege boundaries).\n\t•\tCall out security-critical components and assumptions that must hold for the system to remain secure.\n\nGuidance for Security Analysis\n\nStructure the summary so an application security engineer can quickly answer questions such as:\n\t•\tWhere does user input originate?\n\t•\tHow is untrusted data parsed, validated, and handled?\n\t•\tWhat security assumptions should not be violated?\n\t•\tWhere are the most likely choke points for security bugs?\n\nAdapt the analysis to the project type. For example:\n\t•\tWeb applications: where requests enter, how user data is parsed, routed, authenticated, and stored.\n\t•\tCommand-line tools: supported inputs (arguments, files, environment variables, stdin) and how they are processed.\n\t•\tNetwork daemons: exposed ports, supported protocols, message formats, and request handling paths.\n\t•\tOperating system or low-level components: common vulnerability classes (e.g., memory corruption, logic flaws) that could lead to LPE or RCE.\n\nBe thorough but pragmatic: the goal is to help a security engineer quickly determine whether a discovered bug is security-relevant and where deeper investigation should focus.\n\nTooling Notes\n\nIf Ripgrep (rg) is available, use it to explore the codebase. When using grep or rg, always include the -I flag to avoid searching through binary files.\n```\n\n\n\n## User prompt template\n\nUse this as the task prompt, filling in what you know and marking the rest as assumptions:\n\n```text\n# Inputs\nContext (fill as available; otherwise infer and mark assumptions):\n- intended_usage: {intended_usage}\n- deployment_model: {deployment_model}\n- data_sensitivity: {data_sensitivity}\n- internet_exposure: {internet_exposure}\n- authn_authz_expectations: {authn_authz_expectations}\n- out_of_scope: {out_of_scope}\n\nProvided summaries (may be incomplete):\n- repository_summary: {repository_summary}\n\n\nIn-scope code locations (if known):\n- in_scope_paths: {in_scope_paths}\n\n# Task\nConstruct a repo-centric threat model that helps AppSec engineers understand the most important security risks and where to focus manual review.\n\nYou MUST follow this process and reflect outputs in the final document:\n\n## Process\n1) Repo discovery (evidence collection)\n   a. Identify the repo shape:\n      - languages and frameworks\n      - how it runs (server/cli/library), entrypoints, build artifacts\n   b. Identify security-relevant surfaces and controls by searching for evidences, such as:\n      - network listeners/routes/endpoints; RPC handlers; message consumers\n      - authentication, session/token handling, authorization checks, RBAC/ACL logic\n      - parsing/serialization/deserialization (JSON/YAML/XML/protobuf), template rendering, eval/dynamic code\n      - file upload/read paths, archive extraction, image/document parsing\n      - database/queue/cache clients and query construction\n      - secrets/config loading, environment variables, key management\n      - SSRF-capable HTTP clients, webhooks, URL fetchers\n      - sandboxing/isolation, privilege boundaries, subprocess execution\n      - logging/auditing and error handling paths\n      - CI/build/release: pipelines, dependency management, artifact publishing\n\n2) System model\n   a. Summarize the primary components (runtime plus critical build/CI components when relevant).\n   b. Enumerate data flows and trust boundaries.\n      - For each trust boundary, specify:\n        * source to destination\n        * data types crossing (e.g., credentials, PII, files, tokens, prompts)\n        * channel/protocol (HTTP/gRPC/IPC/file/db)\n        * security guarantees and validation (auth, mTLS, origin checks, schema validation, rate limits)\n   c. Provide a compact Mermaid diagram showing components and trust boundaries.\n\n3) Assets and security objectives\n   - List assets (data, credentials, integrity-critical state, availability-critical components, build artifacts).\n   - For each asset, state why it matters (confidentiality/integrity/availability, compliance, user harm).\n\n4) Attacker model\n   - Capabilities: realistic remote attacker assumptions based on intended usage and exposure.\n   - Non-capabilities: things attacker cannot plausibly do (unless explicitly in scope), to avoid inflated severity.\n\n5) Threat enumeration (concrete, system-specific)\n   - Generate threats as attacker stories tied to:\n     * entry points\n     * trust boundaries\n     * privileged components\n   - Prefer abuse paths (multi-step sequences) over single-line generic threats.\n\n6) Risk prioritization\n   - For each threat:\n     * Likelihood: low/medium/high with a 1 to 2 sentence justification\n     * Impact: low/medium/high with a 1 to 2 sentence justification\n     * Overall priority: critical/high/medium/low (based on likelihood x impact, adjusted for existing controls)\n   - Explicitly state which assumptions most affect risk.\n\n7) Validate assumptions and service context with the user (required before final report)\n   - Summarize key assumptions that materially affect scope or risk ranking.\n   - Ask 1 to 3 targeted questions to resolve missing service meta-context (service owner/environment, scale/users, deployment model, authn/authz, internet exposure, data sensitivity, multi-tenancy).\n   - Pause and wait for user feedback before producing the final report.\n   - If the user cannot answer, proceed with explicit assumptions and mark any conditional conclusions.\n\n8) Mitigations and recommendations\n   - For each high/critical threat:\n     * Existing mitigations (with evidence anchors)\n     * Gaps/weaknesses\n     * Recommended mitigations (code/config/process)\n     * Detection/monitoring ideas (logging, metrics, alerts)\n\n9) Focus paths for manual security review\n   - Output 2 to 30 repo-relative paths (files or directories) that merit deeper review.\n   - For each path, give a one-sentence reason tied to the threat model.\n\n10) Quality check\n   - Provide a short checklist confirming you covered:\n     * all entry points you discovered\n     * each trust boundary at least once in threats\n     * runtime vs CI/dev separation\n     * user clarifications (or explicit non-responses)\n     * assumptions and open questions\n\n## Required output format (exact)\nBefore producing the final Markdown report, first provide an assumption-validation check-in:\n- List the key assumptions in 3 to 6 bullets.\n- Ask 1 to 3 targeted context questions.\n- Wait for the user response, then produce the final report below using the clarified context.\n\nProduce valid Markdown with these sections in this order:\n\n## Executive summary\n- 1 short paragraph on the top risk themes and highest-risk areas.\n\n## Scope and assumptions\n- In-scope paths, out-of-scope items, and explicit assumptions.\n- A short list of open questions that would materially change the risk ranking.\n\n\n## System model\n### Primary components\n### Data flows and trust boundaries\nRepresent the system as a sequence of arrow-style bullets (e.g., Internet → API Server, User Input -> Application Logic, etc). For each boundary, document:\n\t•\tthe primary data types crossing the boundary,\n\t•\tthe communication channel or protocol,\n\t•\tthe security guarantees (e.g., authentication, origin checks, encryption, rate limiting), and\n\t•\tany input validation, normalization, or schema enforcement performed.\n\n#### Diagram\n- Include a single, compact Mermaid diagram (`flowchart TD` or `flowchart LR`) showing primary components and trust boundaries (e.g., separate trust zones via subgraphs). Keep it compact, use only `-->`, avoid `title`/`style`, keep node labels short (no paths/URLs), and keep edge labels to plain words only (avoid `{}`, `[]`, `()`, or quotes).\n\n\n## Assets and security objectives\n- A table: Asset | Why it matters | Security objective (C/I/A)\n\n## Attacker model\n### Capabilities\n### Non-capabilities\n\n## Entry points and attack surfaces\n- A table: Surface | How reached | Trust boundary | Notes | Evidence (repo path / symbol)\n\n## Top abuse paths\n- 5 to 10 short abuse paths, each as a numbered sequence of steps (attacker goal -> steps -> impact).\n\n## Threat model table\n- A Markdown table with columns:\n  Threat ID | Threat source | Prerequisites | Threat action | Impact | Impacted assets | Existing controls (evidence) | Gaps | Recommended mitigations | Detection ideas | Likelihood | Impact severity | Priority\n\nRules:\n- Threat IDs must be stable and formatted: TM-001, TM-002, ...\n- Priority must be one of: critical, high, medium, low.\n- Keep prerequisites to 1 to 2 sentences. Keep recommended mitigations concrete.\n\n## Criticality calibration\n- Define what counts as critical/high/medium/low for THIS repo and context.\n- Include 2 to 3 examples per level (tailored to the repo's assets and exposure).\n\n## Focus paths for security review\n- A table: Path | Why it matters | Related Threat IDs\n\n## Notes on use\n\n- Fill in known context, but allow the model to infer and mark assumptions.\n- Include 1–2 repo-path anchors per major claim; do not dump every match.\n","core/skills/builtin/security-threat-model/references/security-controls-and-assets.md":"# Security Controls and Asset Categories\n\nUse this as a lightweight checklist to keep outputs consistent across teams. Prefer concrete, system-specific items over generic text.\n\n## Asset categories (pick only what applies)\n- User data (PII, content, uploads)\n- Authentication artifacts (passwords, tokens, sessions, cookies)\n- Authorization state (roles, policies, ACLs)\n- Secrets and keys (API keys, signing keys, encryption keys)\n- Configuration and feature flags\n- Models and weights (if ML systems)\n- Source code and build artifacts\n- Audit logs and telemetry\n- Availability-critical resources (queues, caches, rate limits, compute budgets)\n- Tenant isolation boundaries and metadata\n\n## Security control categories\n- Identity and access: authN, authZ, session handling, mTLS, key rotation\n- Input protection: schema validation, parsing hardening, upload scanning, sandboxing\n- Network safeguards: TLS, network policies, WAF, rate limiting, DoS controls\n- Data protection: encryption at rest/in transit, tokenization, redaction\n- Isolation: process sandboxing, container boundaries, tenant isolation, seccomp\n- Observability: audit logs, alerting, anomaly detection, tamper resistance\n- Supply chain: dependency pinning, SBOMs, provenance, signing\n- Change control: CI checks, deployment approvals, config guardrails\n\n## Mitigation phrasing patterns\n- \"Enforce schema at <boundary> for <payload> before <component>.\"\n- \"Require authZ check for <action> on <resource> in <service>.\"\n- \"Isolate <parser/component> in a sandbox with <resource limits>.\"\n- \"Rate limit <endpoint> by <key> and apply burst caps.\"\n- \"Encrypt <data> at rest using <key management> and rotate <keys>.\"\n","core/skills/builtin/skill-creator/SKILL.md":"---\nname: skill-creator\ndescription: Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Codex's capabilities with specialized knowledge, workflows, or tool integrations.\nmetadata:\n  short-description: Create or update a skill\n---\n\n# Skill Creator\n\nThis skill provides guidance for creating effective skills.\n\n## About Skills\n\nSkills are modular, self-contained folders that extend Codex's capabilities by providing\nspecialized knowledge, workflows, and tools. Think of them as \"onboarding guides\" for specific\ndomains or tasks—they transform Codex from a general-purpose agent into a specialized agent\nequipped with procedural knowledge that no model can fully possess.\n\n### What Skills Provide\n\n1. Specialized workflows - Multi-step procedures for specific domains\n2. Tool integrations - Instructions for working with specific file formats or APIs\n3. Domain expertise - Company-specific knowledge, schemas, business logic\n4. Bundled resources - Scripts, references, and assets for complex and repetitive tasks\n\n## Core Principles\n\n### Concise is Key\n\nThe context window is a public good. Skills share the context window with everything else Codex needs: system prompt, conversation history, other Skills' metadata, and the actual user request.\n\n**Default assumption: Codex is already very smart.** Only add context Codex doesn't already have. Challenge each piece of information: \"Does Codex really need this explanation?\" and \"Does this paragraph justify its token cost?\"\n\nPrefer concise examples over verbose explanations.\n\n### Set Appropriate Degrees of Freedom\n\nMatch the level of specificity to the task's fragility and variability:\n\n**High freedom (text-based instructions)**: Use when multiple approaches are valid, decisions depend on context, or heuristics guide the approach.\n\n**Medium freedom (pseudocode or scripts with parameters)**: Use when a preferred pattern exists, some variation is acceptable, or configuration affects behavior.\n\n**Low freedom (specific scripts, few parameters)**: Use when operations are fragile and error-prone, consistency is critical, or a specific sequence must be followed.\n\nThink of Codex as exploring a path: a narrow bridge with cliffs needs specific guardrails (low freedom), while an open field allows many routes (high freedom).\n\n### Anatomy of a Skill\n\nEvery skill consists of a required SKILL.md file and optional bundled resources:\n\n```\nskill-name/\n├── SKILL.md (required)\n│   ├── YAML frontmatter metadata (required)\n│   │   ├── name: (required)\n│   │   └── description: (required)\n│   └── Markdown instructions (required)\n├── agents/ (recommended)\n│   └── openai.yaml - UI metadata for skill lists and chips\n└── Bundled Resources (optional)\n    ├── scripts/          - Executable code (Python/Bash/etc.)\n    ├── references/       - Documentation intended to be loaded into context as needed\n    └── assets/           - Files used in output (templates, icons, fonts, etc.)\n```\n\n#### SKILL.md (required)\n\nEvery SKILL.md consists of:\n\n- **Frontmatter** (YAML): Contains `name` and `description` fields. These are the only fields that Codex reads to determine when the skill gets used, thus it is very important to be clear and comprehensive in describing what the skill is, and when it should be used.\n- **Body** (Markdown): Instructions and guidance for using the skill. Only loaded AFTER the skill triggers (if at all).\n\n#### Agents metadata (recommended)\n\n- UI-facing metadata for skill lists and chips\n- Read references/openai_yaml.md before generating values and follow its descriptions and constraints\n- Create: human-facing `display_name`, `short_description`, and `default_prompt` by reading the skill\n- Generate deterministically by passing the values as `--interface key=value` to `scripts/generate_openai_yaml.py` or `scripts/init_skill.py`\n- On updates: validate `agents/openai.yaml` still matches SKILL.md; regenerate if stale\n- Only include other optional interface fields (icons, brand color) if explicitly provided\n- See references/openai_yaml.md for field definitions and examples\n\n#### Bundled Resources (optional)\n\n##### Scripts (`scripts/`)\n\nExecutable code (Python/Bash/etc.) for tasks that require deterministic reliability or are repeatedly rewritten.\n\n- **When to include**: When the same code is being rewritten repeatedly or deterministic reliability is needed\n- **Example**: `scripts/rotate_pdf.py` for PDF rotation tasks\n- **Benefits**: Token efficient, deterministic, may be executed without loading into context\n- **Note**: Scripts may still need to be read by Codex for patching or environment-specific adjustments\n\n##### References (`references/`)\n\nDocumentation and reference material intended to be loaded as needed into context to inform Codex's process and thinking.\n\n- **When to include**: For documentation that Codex should reference while working\n- **Examples**: `references/finance.md` for financial schemas, `references/mnda.md` for company NDA template, `references/policies.md` for company policies, `references/api_docs.md` for API specifications\n- **Use cases**: Database schemas, API documentation, domain knowledge, company policies, detailed workflow guides\n- **Benefits**: Keeps SKILL.md lean, loaded only when Codex determines it's needed\n- **Best practice**: If files are large (>10k words), include grep search patterns in SKILL.md\n- **Avoid duplication**: Information should live in either SKILL.md or references files, not both. Prefer references files for detailed information unless it's truly core to the skill—this keeps SKILL.md lean while making information discoverable without hogging the context window. Keep only essential procedural instructions and workflow guidance in SKILL.md; move detailed reference material, schemas, and examples to references files.\n\n##### Assets (`assets/`)\n\nFiles not intended to be loaded into context, but rather used within the output Codex produces.\n\n- **When to include**: When the skill needs files that will be used in the final output\n- **Examples**: `assets/logo.png` for brand assets, `assets/slides.pptx` for PowerPoint templates, `assets/frontend-template/` for HTML/React boilerplate, `assets/font.ttf` for typography\n- **Use cases**: Templates, images, icons, boilerplate code, fonts, sample documents that get copied or modified\n- **Benefits**: Separates output resources from documentation, enables Codex to use files without loading them into context\n\n#### What to Not Include in a Skill\n\nA skill should only contain essential files that directly support its functionality. Do NOT create extraneous documentation or auxiliary files, including:\n\n- README.md\n- INSTALLATION_GUIDE.md\n- QUICK_REFERENCE.md\n- CHANGELOG.md\n- etc.\n\nThe skill should only contain the information needed for an AI agent to do the job at hand. It should not contain auxiliary context about the process that went into creating it, setup and testing procedures, user-facing documentation, etc. Creating additional documentation files just adds clutter and confusion.\n\n### Progressive Disclosure Design Principle\n\nSkills use a three-level loading system to manage context efficiently:\n\n1. **Metadata (name + description)** - Always in context (~100 words)\n2. **SKILL.md body** - When skill triggers (<5k words)\n3. **Bundled resources** - As needed by Codex (Unlimited because scripts can be executed without reading into context window)\n\n#### Progressive Disclosure Patterns\n\nKeep SKILL.md body to the essentials and under 500 lines to minimize context bloat. Split content into separate files when approaching this limit. When splitting out content into other files, it is very important to reference them from SKILL.md and describe clearly when to read them, to ensure the reader of the skill knows they exist and when to use them.\n\n**Key principle:** When a skill supports multiple variations, frameworks, or options, keep only the core workflow and selection guidance in SKILL.md. Move variant-specific details (patterns, examples, configuration) into separate reference files.\n\n**Pattern 1: High-level guide with references**\n\n```markdown\n# PDF Processing\n\n## Quick start\n\nExtract text with pdfplumber:\n[code example]\n\n## Advanced features\n\n- **Form filling**: See [FORMS.md](FORMS.md) for complete guide\n- **API reference**: See [REFERENCE.md](REFERENCE.md) for all methods\n- **Examples**: See [EXAMPLES.md](EXAMPLES.md) for common patterns\n```\n\nCodex loads FORMS.md, REFERENCE.md, or EXAMPLES.md only when needed.\n\n**Pattern 2: Domain-specific organization**\n\nFor Skills with multiple domains, organize content by domain to avoid loading irrelevant context:\n\n```\nbigquery-skill/\n├── SKILL.md (overview and navigation)\n└── reference/\n    ├── finance.md (revenue, billing metrics)\n    ├── sales.md (opportunities, pipeline)\n    ├── product.md (API usage, features)\n    └── marketing.md (campaigns, attribution)\n```\n\nWhen a user asks about sales metrics, Codex only reads sales.md.\n\nSimilarly, for skills supporting multiple frameworks or variants, organize by variant:\n\n```\ncloud-deploy/\n├── SKILL.md (workflow + provider selection)\n└── references/\n    ├── aws.md (AWS deployment patterns)\n    ├── gcp.md (GCP deployment patterns)\n    └── azure.md (Azure deployment patterns)\n```\n\nWhen the user chooses AWS, Codex only reads aws.md.\n\n**Pattern 3: Conditional details**\n\nShow basic content, link to advanced content:\n\n```markdown\n# DOCX Processing\n\n## Creating documents\n\nUse docx-js for new documents. See [DOCX-JS.md](DOCX-JS.md).\n\n## Editing documents\n\nFor simple edits, modify the XML directly.\n\n**For tracked changes**: See [REDLINING.md](REDLINING.md)\n**For OOXML details**: See [OOXML.md](OOXML.md)\n```\n\nCodex reads REDLINING.md or OOXML.md only when the user needs those features.\n\n**Important guidelines:**\n\n- **Avoid deeply nested references** - Keep references one level deep from SKILL.md. All reference files should link directly from SKILL.md.\n- **Structure longer reference files** - For files longer than 100 lines, include a table of contents at the top so Codex can see the full scope when previewing.\n\n## Skill Creation Process\n\nSkill creation involves these steps:\n\n1. Understand the skill with concrete examples\n2. Plan reusable skill contents (scripts, references, assets)\n3. Initialize the skill (run init_skill.py)\n4. Edit the skill (implement resources and write SKILL.md)\n5. Validate the skill (run quick_validate.py)\n6. Iterate based on real usage\n\nFollow these steps in order, skipping only if there is a clear reason why they are not applicable.\n\n### Skill Naming\n\n- Use lowercase letters, digits, and hyphens only; normalize user-provided titles to hyphen-case (e.g., \"Plan Mode\" -> `plan-mode`).\n- When generating names, generate a name under 64 characters (letters, digits, hyphens).\n- Prefer short, verb-led phrases that describe the action.\n- Namespace by tool when it improves clarity or triggering (e.g., `gh-address-comments`, `linear-address-issue`).\n- Name the skill folder exactly after the skill name.\n\n### Step 1: Understanding the Skill with Concrete Examples\n\nSkip this step only when the skill's usage patterns are already clearly understood. It remains valuable even when working with an existing skill.\n\nTo create an effective skill, clearly understand concrete examples of how the skill will be used. This understanding can come from either direct user examples or generated examples that are validated with user feedback.\n\nFor example, when building an image-editor skill, relevant questions include:\n\n- \"What functionality should the image-editor skill support? Editing, rotating, anything else?\"\n- \"Can you give some examples of how this skill would be used?\"\n- \"I can imagine users asking for things like 'Remove the red-eye from this image' or 'Rotate this image'. Are there other ways you imagine this skill being used?\"\n- \"What would a user say that should trigger this skill?\"\n\nTo avoid overwhelming users, avoid asking too many questions in a single message. Start with the most important questions and follow up as needed for better effectiveness.\n\nConclude this step when there is a clear sense of the functionality the skill should support.\n\n### Step 2: Planning the Reusable Skill Contents\n\nTo turn concrete examples into an effective skill, analyze each example by:\n\n1. Considering how to execute on the example from scratch\n2. Identifying what scripts, references, and assets would be helpful when executing these workflows repeatedly\n\nExample: When building a `pdf-editor` skill to handle queries like \"Help me rotate this PDF,\" the analysis shows:\n\n1. Rotating a PDF requires re-writing the same code each time\n2. A `scripts/rotate_pdf.py` script would be helpful to store in the skill\n\nExample: When designing a `frontend-webapp-builder` skill for queries like \"Build me a todo app\" or \"Build me a dashboard to track my steps,\" the analysis shows:\n\n1. Writing a frontend webapp requires the same boilerplate HTML/React each time\n2. An `assets/hello-world/` template containing the boilerplate HTML/React project files would be helpful to store in the skill\n\nExample: When building a `big-query` skill to handle queries like \"How many users have logged in today?\" the analysis shows:\n\n1. Querying BigQuery requires re-discovering the table schemas and relationships each time\n2. A `references/schema.md` file documenting the table schemas would be helpful to store in the skill\n\nTo establish the skill's contents, analyze each concrete example to create a list of the reusable resources to include: scripts, references, and assets.\n\n### Step 3: Initializing the Skill\n\nAt this point, it is time to actually create the skill.\n\nSkip this step only if the skill being developed already exists. In this case, continue to the next step.\n\nWhen creating a new skill from scratch, always run the `init_skill.py` script. The script conveniently generates a new template skill directory that automatically includes everything a skill requires, making the skill creation process much more efficient and reliable.\n\nUsage:\n\n```bash\nscripts/init_skill.py <skill-name> --path <output-directory> [--resources scripts,references,assets] [--examples]\n```\n\nExamples:\n\n```bash\nscripts/init_skill.py my-skill --path skills/public\nscripts/init_skill.py my-skill --path skills/public --resources scripts,references\nscripts/init_skill.py my-skill --path skills/public --resources scripts --examples\n```\n\nThe script:\n\n- Creates the skill directory at the specified path\n- Generates a SKILL.md template with proper frontmatter and TODO placeholders\n- Creates `agents/openai.yaml` using agent-generated `display_name`, `short_description`, and `default_prompt` passed via `--interface key=value`\n- Optionally creates resource directories based on `--resources`\n- Optionally adds example files when `--examples` is set\n\nAfter initialization, customize the SKILL.md and add resources as needed. If you used `--examples`, replace or delete placeholder files.\n\nGenerate `display_name`, `short_description`, and `default_prompt` by reading the skill, then pass them as `--interface key=value` to `init_skill.py` or regenerate with:\n\n```bash\nscripts/generate_openai_yaml.py <path/to/skill-folder> --interface key=value\n```\n\nOnly include other optional interface fields when the user explicitly provides them. For full field descriptions and examples, see references/openai_yaml.md.\n\n### Step 4: Edit the Skill\n\nWhen editing the (newly-generated or existing) skill, remember that the skill is being created for another instance of Codex to use. Include information that would be beneficial and non-obvious to Codex. Consider what procedural knowledge, domain-specific details, or reusable assets would help another Codex instance execute these tasks more effectively.\n\n#### Start with Reusable Skill Contents\n\nTo begin implementation, start with the reusable resources identified above: `scripts/`, `references/`, and `assets/` files. Note that this step may require user input. For example, when implementing a `brand-guidelines` skill, the user may need to provide brand assets or templates to store in `assets/`, or documentation to store in `references/`.\n\nAdded scripts must be tested by actually running them to ensure there are no bugs and that the output matches what is expected. If there are many similar scripts, only a representative sample needs to be tested to ensure confidence that they all work while balancing time to completion.\n\nIf you used `--examples`, delete any placeholder files that are not needed for the skill. Only create resource directories that are actually required.\n\n#### Update SKILL.md\n\n**Writing Guidelines:** Always use imperative/infinitive form.\n\n##### Frontmatter\n\nWrite the YAML frontmatter with `name` and `description`:\n\n- `name`: The skill name\n- `description`: This is the primary triggering mechanism for your skill, and helps Codex understand when to use the skill.\n  - Include both what the Skill does and specific triggers/contexts for when to use it.\n  - Include all \"when to use\" information here - Not in the body. The body is only loaded after triggering, so \"When to Use This Skill\" sections in the body are not helpful to Codex.\n  - Example description for a `docx` skill: \"Comprehensive document creation, editing, and analysis with support for tracked changes, comments, formatting preservation, and text extraction. Use when Codex needs to work with professional documents (.docx files) for: (1) Creating new documents, (2) Modifying or editing content, (3) Working with tracked changes, (4) Adding comments, or any other document tasks\"\n\nDo not include any other fields in YAML frontmatter.\n\n##### Body\n\nWrite instructions for using the skill and its bundled resources.\n\n### Step 5: Validate the Skill\n\nOnce development of the skill is complete, validate the skill folder to catch basic issues early:\n\n```bash\nscripts/quick_validate.py <path/to/skill-folder>\n```\n\nThe validation script checks YAML frontmatter format, required fields, and naming rules. If validation fails, fix the reported issues and run the command again.\n\n### Step 6: Iterate\n\nAfter testing the skill, users may request improvements. Often this happens right after using the skill, with fresh context of how the skill performed.\n\n**Iteration workflow:**\n\n1. Use the skill on real tasks\n2. Notice struggles or inefficiencies\n3. Identify how SKILL.md or bundled resources should be updated\n4. Implement changes and test again\n","core/skills/builtin/skill-creator/agents/openai.yaml":"interface:\n  display_name: \"Skill Creator\"\n  short_description: \"Create or update a skill\"\n  default_prompt: \"Read my repository and create a skill to bootstrap new components for my project.\"\n","core/skills/builtin/skill-creator/references/openai_yaml.md":"# openai.yaml fields (full example + descriptions)\n\n`agents/openai.yaml` is an extended, product-specific config intended for the machine/harness to read, not the agent. Other product-specific config can also live in the `agents/` folder.\n\n## Full example\n\n```yaml\ninterface:\n  display_name: \"Optional user-facing name\"\n  short_description: \"Optional user-facing description\"\n  icon_small: \"./assets/small-400px.png\"\n  icon_large: \"./assets/large-logo.svg\"\n  brand_color: \"#3B82F6\"\n  default_prompt: \"Optional surrounding prompt to use the skill with\"\n\ndependencies:\n  tools:\n    - type: \"mcp\"\n      value: \"github\"\n      description: \"GitHub MCP server\"\n      transport: \"streamable_http\"\n      url: \"https://api.githubcopilot.com/mcp/\"\n```\n\n## Field descriptions and constraints\n\nTop-level constraints:\n\n- Quote all string values.\n- Keep keys unquoted.\n- For `interface.default_prompt`: generate a helpful, short (typically 1 sentence) example starting prompt based on the skill. It must explicitly mention the skill as `$skill-name` (e.g., \"Use $skill-name-here to draft a concise weekly status update.\").\n\n- `interface.display_name`: Human-facing title shown in UI skill lists and chips.\n- `interface.short_description`: Human-facing short UI blurb (25–64 chars) for quick scanning.\n- `interface.icon_small`: Path to a small icon asset (relative to skill dir). Default to `./assets/` and place icons in the skill's `assets/` folder.\n- `interface.icon_large`: Path to a larger logo asset (relative to skill dir). Default to `./assets/` and place icons in the skill's `assets/` folder.\n- `interface.brand_color`: Hex color used for UI accents (e.g., badges).\n- `interface.default_prompt`: Default prompt snippet inserted when invoking the skill.\n- `dependencies.tools[].type`: Dependency category. Only `mcp` is supported for now.\n- `dependencies.tools[].value`: Identifier of the tool or dependency.\n- `dependencies.tools[].description`: Human-readable explanation of the dependency.\n- `dependencies.tools[].transport`: Connection type when `type` is `mcp`.\n- `dependencies.tools[].url`: MCP server URL when `type` is `mcp`.\n","core/skills/builtin/webapp-testing/SKILL.md":"---\nname: webapp-testing\ndescription: Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.\nlicense: Complete terms in LICENSE.txt\n---\n\n# Web Application Testing\n\nTo test local web applications, write native Python Playwright scripts.\n\n**Helper Scripts Available**:\n- `scripts/with_server.py` - Manages server lifecycle (supports multiple servers)\n\n**Always run scripts with `--help` first** to see usage. DO NOT read the source until you try running the script first and find that a customized solution is abslutely necessary. These scripts can be very large and thus pollute your context window. They exist to be called directly as black-box scripts rather than ingested into your context window.\n\n## Decision Tree: Choosing Your Approach\n\n```\nUser task → Is it static HTML?\n    ├─ Yes → Read HTML file directly to identify selectors\n    │         ├─ Success → Write Playwright script using selectors\n    │         └─ Fails/Incomplete → Treat as dynamic (below)\n    │\n    └─ No (dynamic webapp) → Is the server already running?\n        ├─ No → Run: python scripts/with_server.py --help\n        │        Then use the helper + write simplified Playwright script\n        │\n        └─ Yes → Reconnaissance-then-action:\n            1. Navigate and wait for networkidle\n            2. Take screenshot or inspect DOM\n            3. Identify selectors from rendered state\n            4. Execute actions with discovered selectors\n```\n\n## Example: Using with_server.py\n\nTo start a server, run `--help` first, then use the helper:\n\n**Single server:**\n```bash\npython scripts/with_server.py --server \"npm run dev\" --port 5173 -- python your_automation.py\n```\n\n**Multiple servers (e.g., backend + frontend):**\n```bash\npython scripts/with_server.py \\\n  --server \"cd backend && python server.py\" --port 3000 \\\n  --server \"cd frontend && npm run dev\" --port 5173 \\\n  -- python your_automation.py\n```\n\nTo create an automation script, include only Playwright logic (servers are managed automatically):\n```python\nfrom playwright.sync_api import sync_playwright\n\nwith sync_playwright() as p:\n    browser = p.chromium.launch(headless=True) # Always launch chromium in headless mode\n    page = browser.new_page()\n    page.goto('http://localhost:5173') # Server already running and ready\n    page.wait_for_load_state('networkidle') # CRITICAL: Wait for JS to execute\n    # ... your automation logic\n    browser.close()\n```\n\n## Reconnaissance-Then-Action Pattern\n\n1. **Inspect rendered DOM**:\n   ```python\n   page.screenshot(path='/tmp/inspect.png', full_page=True)\n   content = page.content()\n   page.locator('button').all()\n   ```\n\n2. **Identify selectors** from inspection results\n\n3. **Execute actions** using discovered selectors\n\n## Common Pitfall\n\n❌ **Don't** inspect the DOM before waiting for `networkidle` on dynamic apps\n✅ **Do** wait for `page.wait_for_load_state('networkidle')` before inspection\n\n## Best Practices\n\n- **Use bundled scripts as black boxes** - To accomplish a task, consider whether one of the scripts available in `scripts/` can help. These scripts handle common, complex workflows reliably without cluttering the context window. Use `--help` to see usage, then invoke directly.\n- Use `sync_playwright()` for synchronous scripts\n- Always close the browser when done\n- Use descriptive selectors: `text=`, `role=`, CSS selectors, or IDs\n- Add appropriate waits: `page.wait_for_selector()` or `page.wait_for_timeout()`\n\n## Reference Files\n\n- **examples/** - Examples showing common patterns:\n  - `element_discovery.py` - Discovering buttons, links, and inputs on a page\n  - `static_html_automation.py` - Using file:// URLs for local HTML\n  - `console_logging.py` - Capturing console logs during automation\n"},"items":[{"name":"SKILL.md","path":"core/skills/builtin/frontend-design/SKILL.md","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/frontend-design/SKILL.md","title":"frontend-design","category":"anthropic-skill","format":"markdown","content":"---\nname: frontend-design\ndescription: Guidance for distinctive, intentional visual design when building new UI or reshaping an existing one. Helps with aesthetic direction, typography, and making choices that don't read as templated defaults.\nlicense: Complete terms in LICENSE.txt\n---\n\n# Frontend Design\n\nApproach this as the design lead at a small studio known for giving every client a visual identity that could not be mistaken for anyone else's. This client has already rejected proposals that felt templated, and is paying for a distinctive point of view: make deliberate, opinionated choices about palette, typography, and layout that are specific to this brief, and take one real aesthetic risk you can justify.\n\n## Ground it in the subject\n\nIf the brief does not pin down what the product or subject is, pin it yourself before designing: name one concrete subject, its audience, and the page's single job, and state your choice. If there's any information in your memory about the human's preferences, context about what they're building, or designs you've made before – use that as a hint. The subject's own world, its materials, instruments, artifacts, and vernacular, is where distinctive choices come from. Build with the brief's real content and subject matter throughout.\n\n## Design principles\n\nFor web designs, the hero is a thesis. Open with the most characteristic thing in the subject's world, in whatever form makes sense for it: a headline, an image, an animation, a live demo, an interactive moment. Be deliberate with your choice: a big number with a small label, supporting stats, and a gradient accent is the template answer, only use if that's truly the best option.\n\nTypography carries the personality of the page. Pair the display and body faces deliberately, not the same families you would reach for on any other project, and set a clear type scale with intentional weights, widths, and spacing. Make the type treatment itself a memorable part of the design, not a neutral delivery vehicle for the content.\n\nStructure is information. Structural devices, numbering, eyebrows, dividers, labels, should encode something true about the content, not decorate it. Many generic designs use numbered markers (01 / 02 / 03), but that's only appropriate if the content actually is a sequence - like a real process or a typed timeline where order carries information the reader needs. Question if choices like numbered markers actually make sense before incorporating them.\n\nLeverage motion deliberately. Think about where and if animation can serve the subject: a page-load sequence, a scroll-triggered reveal, hover micro-interactions, ambient atmosphere. An orchestrated moment usually lands harder than scattered effects; choose what the direction calls for. However, sometimes less is more, and extra animation contributes to the feeling that the design is AI-generated.\n\nMatch complexity to the vision. Maximalist directions need elaborate execution; minimal directions need precision in spacing, type, and detail. Elegance is executing the chosen vision well.\n\nConsider written content carefully. Often a design brief may not contain real content, and it's up to you to come up with copy. Copy can make a design feel as templated as the design itself. See the below section on writing for more guidance.\n\n## Process: brainstorm, explore, plan, critique, build, critique again\n\nFor calibration: AI-generated design right now clusters around three looks: (1) a warm cream background (near #F4F1EA) with a high-contrast serif display and a terracotta accent; (2) a near-black background with a single bright acid-green or vermilion accent; (3) a broadsheet-style layout with hairline rules, zero border-radius, and dense newspaper-like columns. All three are legitimate for some briefs, but they are defaults rather than choices, and they appear regardless of subject. Where the brief pins down a visual direction, follow it exactly — the brief's own words always win, including when it asks for one of these looks. Where it leaves an axis free, don't spend that freedom on one of these defaults. Just like a human designer who's hired, there's often a careful balance between doing what you're good at and taking each project as a chance to experiment and learn.\n\nWork in two passes. First, brainstorm a short design plan based on the human's design brief: create a compact token system with color, type, layout, and signature. Color: describe the palette as 4–6 named hex values. Type: the typefaces for 2+ roles (a characterful display face that's used with restraint, a complementary body face, and a utility face for captions or data if needed). Layout: a layout concept, using one-sentence prose descriptions and ASCII wireframes to ideate and compare. Signature: the single unique element this page will be remembered by that embodies the brief in an appropriate way.\n\nThen review that plan against the brief before building: if any part of it reads like the generic default you would produce for any similar page (work through a similar prompt to see if you arrive somewhere similar) rather than a choice made for this specific brief — revise that part, say what you changed and why. Only after you've confirmed the relative uniqueness of your design plan should you start to write the code, following the revised plan exactly and deriving every color and type decision from it.\n\nWhen writing the code, be careful of structuring your CSS selector specificities. It's easy to generate CSS classes that cancel each other out (especially with a type-based selector like .section and a element-based selector like .cta). This can happen often with paddings/margins between sections.\n\nTry to do a lot of this planning and iteration in your thinking, and only show ideas to the user when you have higher confidence it'll delight them.\n\n## Restraint and self-critique\n\nSpend your boldness in one place. Let the signature element be the one memorable thing, keep everything around it quiet and disciplined, and cut any decoration that does not serve the brief. Not taking a risk can be a risk itself! Build to a quality floor without announcing it: responsive down to mobile, visible keyboard focus, reduced motion respected. Critique your own work as you build, taking screenshots if your environment supports it – a picture is worth 1000 tokens. Consider Chanel's advice: before leaving the house, take a look in the mirror and remove one accessory. Human creators have memory and always try to do something new, so if you have a space to quickly jot down notes about what you've tried, it can help you in future passes.\n\n## More on writing in design\n\nWords appear in a design for one reason: to make it easier to understand, and therefore easier to use. They are design material, not decoration. Bring the same intentionality to copy that you would bring to spacing and color. Before writing anything, ask what the design needs to say, and how it can best be said to help the person navigate the experience.\n\nWrite from the end user's side of the screen. Name things by what people control and recognize, never by how the system is built. A person manages notifications, not webhook config. Describe what something does in plain terms rather than selling it. Being specific is always better than being clever.\n\nUse active voice as default. A control should say exactly what happens when it's used: \"Save changes,\" not \"Submit.\" An action keeps the same name through the whole flow, so the button that says \"Publish\" produces a toast that says \"Published.\" The vocabulary of an interface is the signposting for someone navigating the product. Cohesion and consistency are how people learn their way around.\n\nTreat failure and emptiness as moments for direction, not mood. Explain what went wrong and how to fix it, in the interface's voice rather than a person's. Errors don't apologize, and they are never vague about what happened. An empty screen is an invitation to act.\n\nKeep the register conversational and tuned: plain verbs, sentence case, no filler, with tone matched to the brand and the audience. Let each element do exactly one job. A label labels, an example demonstrates, and nothing quietly does double duty.\n","frontmatter":{"name":"frontend-design","description":"Guidance for distinctive, intentional visual design when building new UI or reshaping an existing one. Helps with aesthetic direction, typography, and making choices that don't read as templated defaults.","license":"Complete terms in LICENSE.txt"},"isInternal":false,"tokens":1668,"sizeBytes":8260},{"name":"evaluation.md","path":"core/skills/builtin/mcp-builder/reference/evaluation.md","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/mcp-builder/reference/evaluation.md","title":"Reference Skill","category":"anthropic-skill","format":"markdown","content":"# MCP Server Evaluation Guide\n\n## Overview\n\nThis document provides guidance on creating comprehensive evaluations for MCP servers. Evaluations test whether LLMs can effectively use your MCP server to answer realistic, complex questions using only the tools provided.\n\n---\n\n## Quick Reference\n\n### Evaluation Requirements\n- Create 10 human-readable questions\n- Questions must be READ-ONLY, INDEPENDENT, NON-DESTRUCTIVE\n- Each question requires multiple tool calls (potentially dozens)\n- Answers must be single, verifiable values\n- Answers must be STABLE (won't change over time)\n\n### Output Format\n```xml\n<evaluation>\n   <qa_pair>\n      <question>Your question here</question>\n      <answer>Single verifiable answer</answer>\n   </qa_pair>\n</evaluation>\n```\n\n---\n\n## Purpose of Evaluations\n\nThe measure of quality of an MCP server is NOT how well or comprehensively the server implements tools, but how well these implementations (input/output schemas, docstrings/descriptions, functionality) enable LLMs with no other context and access ONLY to the MCP servers to answer realistic and difficult questions.\n\n## Evaluation Overview\n\nCreate 10 human-readable questions requiring ONLY READ-ONLY, INDEPENDENT, NON-DESTRUCTIVE, and IDEMPOTENT operations to answer. Each question should be:\n- Realistic\n- Clear and concise\n- Unambiguous\n- Complex, requiring potentially dozens of tool calls or steps\n- Answerable with a single, verifiable value that you identify in advance\n\n## Question Guidelines\n\n### Core Requirements\n\n1. **Questions MUST be independent**\n   - Each question should NOT depend on the answer to any other question\n   - Should not assume prior write operations from processing another question\n\n2. **Questions MUST require ONLY NON-DESTRUCTIVE AND IDEMPOTENT tool use**\n   - Should not instruct or require modifying state to arrive at the correct answer\n\n3. **Questions must be REALISTIC, CLEAR, CONCISE, and COMPLEX**\n   - Must require another LLM to use multiple (potentially dozens of) tools or steps to answer\n\n### Complexity and Depth\n\n4. **Questions must require deep exploration**\n   - Consider multi-hop questions requiring multiple sub-questions and sequential tool calls\n   - Each step should benefit from information found in previous questions\n\n5. **Questions may require extensive paging**\n   - May need paging through multiple pages of results\n   - May require querying old data (1-2 years out-of-date) to find niche information\n   - The questions must be DIFFICULT\n\n6. **Questions must require deep understanding**\n   - Rather than surface-level knowledge\n   - May pose complex ideas as True/False questions requiring evidence\n   - May use multiple-choice format where LLM must search different hypotheses\n\n7. **Questions must not be solvable with straightforward keyword search**\n   - Do not include specific keywords from the target content\n   - Use synonyms, related concepts, or paraphrases\n   - Require multiple searches, analyzing multiple related items, extracting context, then deriving the answer\n\n### Tool Testing\n\n8. **Questions should stress-test tool return values**\n   - May elicit tools returning large JSON objects or lists, overwhelming the LLM\n   - Should require understanding multiple modalities of data:\n     - IDs and names\n     - Timestamps and datetimes (months, days, years, seconds)\n     - File IDs, names, extensions, and mimetypes\n     - URLs, GIDs, etc.\n   - Should probe the tool's ability to return all useful forms of data\n\n9. **Questions should MOSTLY reflect real human use cases**\n   - The kinds of information retrieval tasks that HUMANS assisted by an LLM would care about\n\n10. **Questions may require dozens of tool calls**\n    - This challenges LLMs with limited context\n    - Encourages MCP server tools to reduce information returned\n\n11. **Include ambiguous questions**\n    - May be ambiguous OR require difficult decisions on which tools to call\n    - Force the LLM to potentially make mistakes or misinterpret\n    - Ensure that despite AMBIGUITY, there is STILL A SINGLE VERIFIABLE ANSWER\n\n### Stability\n\n12. **Questions must be designed so the answer DOES NOT CHANGE**\n    - Do not ask questions that rely on \"current state\" which is dynamic\n    - For example, do not count:\n      - Number of reactions to a post\n      - Number of replies to a thread\n      - Number of members in a channel\n\n13. **DO NOT let the MCP server RESTRICT the kinds of questions you create**\n    - Create challenging and complex questions\n    - Some may not be solvable with the available MCP server tools\n    - Questions may require specific output formats (datetime vs. epoch time, JSON vs. MARKDOWN)\n    - Questions may require dozens of tool calls to complete\n\n## Answer Guidelines\n\n### Verification\n\n1. **Answers must be VERIFIABLE via direct string comparison**\n   - If the answer can be re-written in many formats, clearly specify the output format in the QUESTION\n   - Examples: \"Use YYYY/MM/DD.\", \"Respond True or False.\", \"Answer A, B, C, or D and nothing else.\"\n   - Answer should be a single VERIFIABLE value such as:\n     - User ID, user name, display name, first name, last name\n     - Channel ID, channel name\n     - Message ID, string\n     - URL, title\n     - Numerical quantity\n     - Timestamp, datetime\n     - Boolean (for True/False questions)\n     - Email address, phone number\n     - File ID, file name, file extension\n     - Multiple choice answer\n   - Answers must not require special formatting or complex, structured output\n   - Answer will be verified using DIRECT STRING COMPARISON\n\n### Readability\n\n2. **Answers should generally prefer HUMAN-READABLE formats**\n   - Examples: names, first name, last name, datetime, file name, message string, URL, yes/no, true/false, a/b/c/d\n   - Rather than opaque IDs (though IDs are acceptable)\n   - The VAST MAJORITY of answers should be human-readable\n\n### Stability\n\n3. **Answers must be STABLE/STATIONARY**\n   - Look at old content (e.g., conversations that have ended, projects that have launched, questions answered)\n   - Create QUESTIONS based on \"closed\" concepts that will always return the same answer\n   - Questions may ask to consider a fixed time window to insulate from non-stationary answers\n   - Rely on context UNLIKELY to change\n   - Example: if finding a paper name, be SPECIFIC enough so answer is not confused with papers published later\n\n4. **Answers must be CLEAR and UNAMBIGUOUS**\n   - Questions must be designed so there is a single, clear answer\n   - Answer can be derived from using the MCP server tools\n\n### Diversity\n\n5. **Answers must be DIVERSE**\n   - Answer should be a single VERIFIABLE value in diverse modalities and formats\n   - User concept: user ID, user name, display name, first name, last name, email address, phone number\n   - Channel concept: channel ID, channel name, channel topic\n   - Message concept: message ID, message string, timestamp, month, day, year\n\n6. **Answers must NOT be complex structures**\n   - Not a list of values\n   - Not a complex object\n   - Not a list of IDs or strings\n   - Not natural language text\n   - UNLESS the answer can be straightforwardly verified using DIRECT STRING COMPARISON\n   - And can be realistically reproduced\n   - It should be unlikely that an LLM would return the same list in any other order or format\n\n## Evaluation Process\n\n### Step 1: Documentation Inspection\n\nRead the documentation of the target API to understand:\n- Available endpoints and functionality\n- If ambiguity exists, fetch additional information from the web\n- Parallelize this step AS MUCH AS POSSIBLE\n- Ensure each subagent is ONLY examining documentation from the file system or on the web\n\n### Step 2: Tool Inspection\n\nList the tools available in the MCP server:\n- Inspect the MCP server directly\n- Understand input/output schemas, docstrings, and descriptions\n- WITHOUT calling the tools themselves at this stage\n\n### Step 3: Developing Understanding\n\nRepeat steps 1 & 2 until you have a good understanding:\n- Iterate multiple times\n- Think about the kinds of tasks you want to create\n- Refine your understanding\n- At NO stage should you READ the code of the MCP server implementation itself\n- Use your intuition and understanding to create reasonable, realistic, but VERY challenging tasks\n\n### Step 4: Read-Only Content Inspection\n\nAfter understanding the API and tools, USE the MCP server tools:\n- Inspect content using READ-ONLY and NON-DESTRUCTIVE operations ONLY\n- Goal: identify specific content (e.g., users, channels, messages, projects, tasks) for creating realistic questions\n- Should NOT call any tools that modify state\n- Will NOT read the code of the MCP server implementation itself\n- Parallelize this step with individual sub-agents pursuing independent explorations\n- Ensure each subagent is only performing READ-ONLY, NON-DESTRUCTIVE, and IDEMPOTENT operations\n- BE CAREFUL: SOME TOOLS may return LOTS OF DATA which would cause you to run out of CONTEXT\n- Make INCREMENTAL, SMALL, AND TARGETED tool calls for exploration\n- In all tool call requests, use the `limit` parameter to limit results (<10)\n- Use pagination\n\n### Step 5: Task Generation\n\nAfter inspecting the content, create 10 human-readable questions:\n- An LLM should be able to answer these with the MCP server\n- Follow all question and answer guidelines above\n\n## Output Format\n\nEach QA pair consists of a question and an answer. The output should be an XML file with this structure:\n\n```xml\n<evaluation>\n   <qa_pair>\n      <question>Find the project created in Q2 2024 with the highest number of completed tasks. What is the project name?</question>\n      <answer>Website Redesign</answer>\n   </qa_pair>\n   <qa_pair>\n      <question>Search for issues labeled as \"bug\" that were closed in March 2024. Which user closed the most issues? Provide their username.</question>\n      <answer>sarah_dev</answer>\n   </qa_pair>\n   <qa_pair>\n      <question>Look for pull requests that modified files in the /api directory and were merged between January 1 and January 31, 2024. How many different contributors worked on these PRs?</question>\n      <answer>7</answer>\n   </qa_pair>\n   <qa_pair>\n      <question>Find the repository with the most stars that was created before 2023. What is the repository name?</question>\n      <answer>data-pipeline</answer>\n   </qa_pair>\n</evaluation>\n```\n\n## Evaluation Examples\n\n### Good Questions\n\n**Example 1: Multi-hop question requiring deep exploration (GitHub MCP)**\n```xml\n<qa_pair>\n   <question>Find the repository that was archived in Q3 2023 and had previously been the most forked project in the organization. What was the primary programming language used in that repository?</question>\n   <answer>Python</answer>\n</qa_pair>\n```\n\nThis question is good because:\n- Requires multiple searches to find archived repositories\n- Needs to identify which had the most forks before archival\n- Requires examining repository details for the language\n- Answer is a simple, verifiable value\n- Based on historical (closed) data that won't change\n\n**Example 2: Requires understanding context without keyword matching (Project Management MCP)**\n```xml\n<qa_pair>\n   <question>Locate the initiative focused on improving customer onboarding that was completed in late 2023. The project lead created a retrospective document after completion. What was the lead's role title at that time?</question>\n   <answer>Product Manager</answer>\n</qa_pair>\n```\n\nThis question is good because:\n- Doesn't use specific project name (\"initiative focused on improving customer onboarding\")\n- Requires finding completed projects from specific timeframe\n- Needs to identify the project lead and their role\n- Requires understanding context from retrospective documents\n- Answer is human-readable and stable\n- Based on completed work (won't change)\n\n**Example 3: Complex aggregation requiring multiple steps (Issue Tracker MCP)**\n```xml\n<qa_pair>\n   <question>Among all bugs reported in January 2024 that were marked as critical priority, which assignee resolved the highest percentage of their assigned bugs within 48 hours? Provide the assignee's username.</question>\n   <answer>alex_eng</answer>\n</qa_pair>\n```\n\nThis question is good because:\n- Requires filtering bugs by date, priority, and status\n- Needs to group by assignee and calculate resolution rates\n- Requires understanding timestamps to determine 48-hour windows\n- Tests pagination (potentially many bugs to process)\n- Answer is a single username\n- Based on historical data from specific time period\n\n**Example 4: Requires synthesis across multiple data types (CRM MCP)**\n```xml\n<qa_pair>\n   <question>Find the account that upgraded from the Starter to Enterprise plan in Q4 2023 and had the highest annual contract value. What industry does this account operate in?</question>\n   <answer>Healthcare</answer>\n</qa_pair>\n```\n\nThis question is good because:\n- Requires understanding subscription tier changes\n- Needs to identify upgrade events in specific timeframe\n- Requires comparing contract values\n- Must access account industry information\n- Answer is simple and verifiable\n- Based on completed historical transactions\n\n### Poor Questions\n\n**Example 1: Answer changes over time**\n```xml\n<qa_pair>\n   <question>How many open issues are currently assigned to the engineering team?</question>\n   <answer>47</answer>\n</qa_pair>\n```\n\nThis question is poor because:\n- The answer will change as issues are created, closed, or reassigned\n- Not based on stable/stationary data\n- Relies on \"current state\" which is dynamic\n\n**Example 2: Too easy with keyword search**\n```xml\n<qa_pair>\n   <question>Find the pull request with title \"Add authentication feature\" and tell me who created it.</question>\n   <answer>developer123</answer>\n</qa_pair>\n```\n\nThis question is poor because:\n- Can be solved with a straightforward keyword search for exact title\n- Doesn't require deep exploration or understanding\n- No synthesis or analysis needed\n\n**Example 3: Ambiguous answer format**\n```xml\n<qa_pair>\n   <question>List all the repositories that have Python as their primary language.</question>\n   <answer>repo1, repo2, repo3, data-pipeline, ml-tools</answer>\n</qa_pair>\n```\n\nThis question is poor because:\n- Answer is a list that could be returned in any order\n- Difficult to verify with direct string comparison\n- LLM might format differently (JSON array, comma-separated, newline-separated)\n- Better to ask for a specific aggregate (count) or superlative (most stars)\n\n## Verification Process\n\nAfter creating evaluations:\n\n1. **Examine the XML file** to understand the schema\n2. **Load each task instruction** and in parallel using the MCP server and tools, identify the correct answer by attempting to solve the task YOURSELF\n3. **Flag any operations** that require WRITE or DESTRUCTIVE operations\n4. **Accumulate all CORRECT answers** and replace any incorrect answers in the document\n5. **Remove any `<qa_pair>`** that require WRITE or DESTRUCTIVE operations\n\nRemember to parallelize solving tasks to avoid running out of context, then accumulate all answers and make changes to the file at the end.\n\n## Tips for Creating Quality Evaluations\n\n1. **Think Hard and Plan Ahead** before generating tasks\n2. **Parallelize Where Opportunity Arises** to speed up the process and manage context\n3. **Focus on Realistic Use Cases** that humans would actually want to accomplish\n4. **Create Challenging Questions** that test the limits of the MCP server's capabilities\n5. **Ensure Stability** by using historical data and closed concepts\n6. **Verify Answers** by solving the questions yourself using the MCP server tools\n7. **Iterate and Refine** based on what you learn during the process\n\n---\n\n# Running Evaluations\n\nAfter creating your evaluation file, you can use the provided evaluation harness to test your MCP server.\n\n## Setup\n\n1. **Install Dependencies**\n\n   ```bash\n   pip install -r scripts/requirements.txt\n   ```\n\n   Or install manually:\n   ```bash\n   pip install anthropic mcp\n   ```\n\n2. **Set API Key**\n\n   ```bash\n   export ANTHROPIC_API_KEY=your_api_key_here\n   ```\n\n## Evaluation File Format\n\nEvaluation files use XML format with `<qa_pair>` elements:\n\n```xml\n<evaluation>\n   <qa_pair>\n      <question>Find the project created in Q2 2024 with the highest number of completed tasks. What is the project name?</question>\n      <answer>Website Redesign</answer>\n   </qa_pair>\n   <qa_pair>\n      <question>Search for issues labeled as \"bug\" that were closed in March 2024. Which user closed the most issues? Provide their username.</question>\n      <answer>sarah_dev</answer>\n   </qa_pair>\n</evaluation>\n```\n\n## Running Evaluations\n\nThe evaluation script (`scripts/evaluation.py`) supports three transport types:\n\n**Important:**\n- **stdio transport**: The evaluation script automatically launches and manages the MCP server process for you. Do not run the server manually.\n- **sse/http transports**: You must start the MCP server separately before running the evaluation. The script connects to the already-running server at the specified URL.\n\n### 1. Local STDIO Server\n\nFor locally-run MCP servers (script launches the server automatically):\n\n```bash\npython scripts/evaluation.py \\\n  -t stdio \\\n  -c python \\\n  -a my_mcp_server.py \\\n  evaluation.xml\n```\n\nWith environment variables:\n```bash\npython scripts/evaluation.py \\\n  -t stdio \\\n  -c python \\\n  -a my_mcp_server.py \\\n  -e API_KEY=abc123 \\\n  -e DEBUG=true \\\n  evaluation.xml\n```\n\n### 2. Server-Sent Events (SSE)\n\nFor SSE-based MCP servers (you must start the server first):\n\n```bash\npython scripts/evaluation.py \\\n  -t sse \\\n  -u https://example.com/mcp \\\n  -H \"Authorization: Bearer token123\" \\\n  -H \"X-Custom-Header: value\" \\\n  evaluation.xml\n```\n\n### 3. HTTP (Streamable HTTP)\n\nFor HTTP-based MCP servers (you must start the server first):\n\n```bash\npython scripts/evaluation.py \\\n  -t http \\\n  -u https://example.com/mcp \\\n  -H \"Authorization: Bearer token123\" \\\n  evaluation.xml\n```\n\n## Command-Line Options\n\n```\nusage: evaluation.py [-h] [-t {stdio,sse,http}] [-m MODEL] [-c COMMAND]\n                     [-a ARGS [ARGS ...]] [-e ENV [ENV ...]] [-u URL]\n                     [-H HEADERS [HEADERS ...]] [-o OUTPUT]\n                     eval_file\n\npositional arguments:\n  eval_file             Path to evaluation XML file\n\noptional arguments:\n  -h, --help            Show help message\n  -t, --transport       Transport type: stdio, sse, or http (default: stdio)\n  -m, --model           Claude model to use (default: claude-3-7-sonnet-20250219)\n  -o, --output          Output file for report (default: print to stdout)\n\nstdio options:\n  -c, --command         Command to run MCP server (e.g., python, node)\n  -a, --args            Arguments for the command (e.g., server.py)\n  -e, --env             Environment variables in KEY=VALUE format\n\nsse/http options:\n  -u, --url             MCP server URL\n  -H, --header          HTTP headers in 'Key: Value' format\n```\n\n## Output\n\nThe evaluation script generates a detailed report including:\n\n- **Summary Statistics**:\n  - Accuracy (correct/total)\n  - Average task duration\n  - Average tool calls per task\n  - Total tool calls\n\n- **Per-Task Results**:\n  - Prompt and expected response\n  - Actual response from the agent\n  - Whether the answer was correct (✅/❌)\n  - Duration and tool call details\n  - Agent's summary of its approach\n  - Agent's feedback on the tools\n\n### Save Report to File\n\n```bash\npython scripts/evaluation.py \\\n  -t stdio \\\n  -c python \\\n  -a my_server.py \\\n  -o evaluation_report.md \\\n  evaluation.xml\n```\n\n## Complete Example Workflow\n\nHere's a complete example of creating and running an evaluation:\n\n1. **Create your evaluation file** (`my_evaluation.xml`):\n\n```xml\n<evaluation>\n   <qa_pair>\n      <question>Find the user who created the most issues in January 2024. What is their username?</question>\n      <answer>alice_developer</answer>\n   </qa_pair>\n   <qa_pair>\n      <question>Among all pull requests merged in Q1 2024, which repository had the highest number? Provide the repository name.</question>\n      <answer>backend-api</answer>\n   </qa_pair>\n   <qa_pair>\n      <question>Find the project that was completed in December 2023 and had the longest duration from start to finish. How many days did it take?</question>\n      <answer>127</answer>\n   </qa_pair>\n</evaluation>\n```\n\n2. **Install dependencies**:\n\n```bash\npip install -r scripts/requirements.txt\nexport ANTHROPIC_API_KEY=your_api_key\n```\n\n3. **Run evaluation**:\n\n```bash\npython scripts/evaluation.py \\\n  -t stdio \\\n  -c python \\\n  -a github_mcp_server.py \\\n  -e GITHUB_TOKEN=ghp_xxx \\\n  -o github_eval_report.md \\\n  my_evaluation.xml\n```\n\n4. **Review the report** in `github_eval_report.md` to:\n   - See which questions passed/failed\n   - Read the agent's feedback on your tools\n   - Identify areas for improvement\n   - Iterate on your MCP server design\n\n## Troubleshooting\n\n### Connection Errors\n\nIf you get connection errors:\n- **STDIO**: Verify the command and arguments are correct\n- **SSE/HTTP**: Check the URL is accessible and headers are correct\n- Ensure any required API keys are set in environment variables or headers\n\n### Low Accuracy\n\nIf many evaluations fail:\n- Review the agent's feedback for each task\n- Check if tool descriptions are clear and comprehensive\n- Verify input parameters are well-documented\n- Consider whether tools return too much or too little data\n- Ensure error messages are actionable\n\n### Timeout Issues\n\nIf tasks are timing out:\n- Use a more capable model (e.g., `claude-3-7-sonnet-20250219`)\n- Check if tools are returning too much data\n- Verify pagination is working correctly\n- Consider simplifying complex questions\n","isInternal":false,"tokens":4939,"sizeBytes":21664},{"name":"mcp_best_practices.md","path":"core/skills/builtin/mcp-builder/reference/mcp_best_practices.md","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/mcp-builder/reference/mcp_best_practices.md","title":"Reference Skill","category":"anthropic-skill","format":"markdown","content":"# MCP Server Best Practices\n\n## Quick Reference\n\n### Server Naming\n- **Python**: `{service}_mcp` (e.g., `slack_mcp`)\n- **Node/TypeScript**: `{service}-mcp-server` (e.g., `slack-mcp-server`)\n\n### Tool Naming\n- Use snake_case with service prefix\n- Format: `{service}_{action}_{resource}`\n- Example: `slack_send_message`, `github_create_issue`\n\n### Response Formats\n- Support both JSON and Markdown formats\n- JSON for programmatic processing\n- Markdown for human readability\n\n### Pagination\n- Always respect `limit` parameter\n- Return `has_more`, `next_offset`, `total_count`\n- Default to 20-50 items\n\n### Transport\n- **Streamable HTTP**: For remote servers, multi-client scenarios\n- **stdio**: For local integrations, command-line tools\n- Avoid SSE (deprecated in favor of streamable HTTP)\n\n---\n\n## Server Naming Conventions\n\nFollow these standardized naming patterns:\n\n**Python**: Use format `{service}_mcp` (lowercase with underscores)\n- Examples: `slack_mcp`, `github_mcp`, `jira_mcp`\n\n**Node/TypeScript**: Use format `{service}-mcp-server` (lowercase with hyphens)\n- Examples: `slack-mcp-server`, `github-mcp-server`, `jira-mcp-server`\n\nThe name should be general, descriptive of the service being integrated, easy to infer from the task description, and without version numbers.\n\n---\n\n## Tool Naming and Design\n\n### Tool Naming\n\n1. **Use snake_case**: `search_users`, `create_project`, `get_channel_info`\n2. **Include service prefix**: Anticipate that your MCP server may be used alongside other MCP servers\n   - Use `slack_send_message` instead of just `send_message`\n   - Use `github_create_issue` instead of just `create_issue`\n3. **Be action-oriented**: Start with verbs (get, list, search, create, etc.)\n4. **Be specific**: Avoid generic names that could conflict with other servers\n\n### Tool Design\n\n- Tool descriptions must narrowly and unambiguously describe functionality\n- Descriptions must precisely match actual functionality\n- Provide tool annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint)\n- Keep tool operations focused and atomic\n\n---\n\n## Response Formats\n\nAll tools that return data should support multiple formats:\n\n### JSON Format (`response_format=\"json\"`)\n- Machine-readable structured data\n- Include all available fields and metadata\n- Consistent field names and types\n- Use for programmatic processing\n\n### Markdown Format (`response_format=\"markdown\"`, typically default)\n- Human-readable formatted text\n- Use headers, lists, and formatting for clarity\n- Convert timestamps to human-readable format\n- Show display names with IDs in parentheses\n- Omit verbose metadata\n\n---\n\n## Pagination\n\nFor tools that list resources:\n\n- **Always respect the `limit` parameter**\n- **Implement pagination**: Use `offset` or cursor-based pagination\n- **Return pagination metadata**: Include `has_more`, `next_offset`/`next_cursor`, `total_count`\n- **Never load all results into memory**: Especially important for large datasets\n- **Default to reasonable limits**: 20-50 items is typical\n\nExample pagination response:\n```json\n{\n  \"total\": 150,\n  \"count\": 20,\n  \"offset\": 0,\n  \"items\": [...],\n  \"has_more\": true,\n  \"next_offset\": 20\n}\n```\n\n---\n\n## Transport Options\n\n### Streamable HTTP\n\n**Best for**: Remote servers, web services, multi-client scenarios\n\n**Characteristics**:\n- Bidirectional communication over HTTP\n- Supports multiple simultaneous clients\n- Can be deployed as a web service\n- Enables server-to-client notifications\n\n**Use when**:\n- Serving multiple clients simultaneously\n- Deploying as a cloud service\n- Integration with web applications\n\n### stdio\n\n**Best for**: Local integrations, command-line tools\n\n**Characteristics**:\n- Standard input/output stream communication\n- Simple setup, no network configuration needed\n- Runs as a subprocess of the client\n\n**Use when**:\n- Building tools for local development environments\n- Integrating with desktop applications\n- Single-user, single-session scenarios\n\n**Note**: stdio servers should NOT log to stdout (use stderr for logging)\n\n### Transport Selection\n\n| Criterion | stdio | Streamable HTTP |\n|-----------|-------|-----------------|\n| **Deployment** | Local | Remote |\n| **Clients** | Single | Multiple |\n| **Complexity** | Low | Medium |\n| **Real-time** | No | Yes |\n\n---\n\n## Security Best Practices\n\n### Authentication and Authorization\n\n**OAuth 2.1**:\n- Use secure OAuth 2.1 with certificates from recognized authorities\n- Validate access tokens before processing requests\n- Only accept tokens specifically intended for your server\n\n**API Keys**:\n- Store API keys in environment variables, never in code\n- Validate keys on server startup\n- Provide clear error messages when authentication fails\n\n### Input Validation\n\n- Sanitize file paths to prevent directory traversal\n- Validate URLs and external identifiers\n- Check parameter sizes and ranges\n- Prevent command injection in system calls\n- Use schema validation (Pydantic/Zod) for all inputs\n\n### Error Handling\n\n- Don't expose internal errors to clients\n- Log security-relevant errors server-side\n- Provide helpful but not revealing error messages\n- Clean up resources after errors\n\n### DNS Rebinding Protection\n\nFor streamable HTTP servers running locally:\n- Enable DNS rebinding protection\n- Validate the `Origin` header on all incoming connections\n- Bind to `127.0.0.1` rather than `0.0.0.0`\n\n---\n\n## Tool Annotations\n\nProvide annotations to help clients understand tool behavior:\n\n| Annotation | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `readOnlyHint` | boolean | false | Tool does not modify its environment |\n| `destructiveHint` | boolean | true | Tool may perform destructive updates |\n| `idempotentHint` | boolean | false | Repeated calls with same args have no additional effect |\n| `openWorldHint` | boolean | true | Tool interacts with external entities |\n\n**Important**: Annotations are hints, not security guarantees. Clients should not make security-critical decisions based solely on annotations.\n\n---\n\n## Error Handling\n\n- Use standard JSON-RPC error codes\n- Report tool errors within result objects (not protocol-level errors)\n- Provide helpful, specific error messages with suggested next steps\n- Don't expose internal implementation details\n- Clean up resources properly on errors\n\nExample error handling:\n```typescript\ntry {\n  const result = performOperation();\n  return { content: [{ type: \"text\", text: result }] };\n} catch (error) {\n  return {\n    isError: true,\n    content: [{\n      type: \"text\",\n      text: `Error: ${error.message}. Try using filter='active_only' to reduce results.`\n    }]\n  };\n}\n```\n\n---\n\n## Testing Requirements\n\nComprehensive testing should cover:\n\n- **Functional testing**: Verify correct execution with valid/invalid inputs\n- **Integration testing**: Test interaction with external systems\n- **Security testing**: Validate auth, input sanitization, rate limiting\n- **Performance testing**: Check behavior under load, timeouts\n- **Error handling**: Ensure proper error reporting and cleanup\n\n---\n\n## Documentation Requirements\n\n- Provide clear documentation of all tools and capabilities\n- Include working examples (at least 3 per major feature)\n- Document security considerations\n- Specify required permissions and access levels\n- Document rate limits and performance characteristics\n","isInternal":false,"tokens":1593,"sizeBytes":7330},{"name":"node_mcp_server.md","path":"core/skills/builtin/mcp-builder/reference/node_mcp_server.md","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/mcp-builder/reference/node_mcp_server.md","title":"Reference Skill","category":"anthropic-skill","format":"markdown","content":"# Node/TypeScript MCP Server Implementation Guide\n\n## Overview\n\nThis document provides Node/TypeScript-specific best practices and examples for implementing MCP servers using the MCP TypeScript SDK. It covers project structure, server setup, tool registration patterns, input validation with Zod, error handling, and complete working examples.\n\n---\n\n## Quick Reference\n\n### Key Imports\n```typescript\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport express from \"express\";\nimport { z } from \"zod\";\n```\n\n### Server Initialization\n```typescript\nconst server = new McpServer({\n  name: \"service-mcp-server\",\n  version: \"1.0.0\"\n});\n```\n\n### Tool Registration Pattern\n```typescript\nserver.registerTool(\n  \"tool_name\",\n  {\n    title: \"Tool Display Name\",\n    description: \"What the tool does\",\n    inputSchema: { param: z.string() },\n    outputSchema: { result: z.string() }\n  },\n  async ({ param }) => {\n    const output = { result: `Processed: ${param}` };\n    return {\n      content: [{ type: \"text\", text: JSON.stringify(output) }],\n      structuredContent: output // Modern pattern for structured data\n    };\n  }\n);\n```\n\n---\n\n## MCP TypeScript SDK\n\nThe official MCP TypeScript SDK provides:\n- `McpServer` class for server initialization\n- `registerTool` method for tool registration\n- Zod schema integration for runtime input validation\n- Type-safe tool handler implementations\n\n**IMPORTANT - Use Modern APIs Only:**\n- **DO use**: `server.registerTool()`, `server.registerResource()`, `server.registerPrompt()`\n- **DO NOT use**: Old deprecated APIs such as `server.tool()`, `server.setRequestHandler(ListToolsRequestSchema, ...)`, or manual handler registration\n- The `register*` methods provide better type safety, automatic schema handling, and are the recommended approach\n\nSee the MCP SDK documentation in the references for complete details.\n\n## Server Naming Convention\n\nNode/TypeScript MCP servers must follow this naming pattern:\n- **Format**: `{service}-mcp-server` (lowercase with hyphens)\n- **Examples**: `github-mcp-server`, `jira-mcp-server`, `stripe-mcp-server`\n\nThe name should be:\n- General (not tied to specific features)\n- Descriptive of the service/API being integrated\n- Easy to infer from the task description\n- Without version numbers or dates\n\n## Project Structure\n\nCreate the following structure for Node/TypeScript MCP servers:\n\n```\n{service}-mcp-server/\n├── package.json\n├── tsconfig.json\n├── README.md\n├── src/\n│   ├── index.ts          # Main entry point with McpServer initialization\n│   ├── types.ts          # TypeScript type definitions and interfaces\n│   ├── tools/            # Tool implementations (one file per domain)\n│   ├── services/         # API clients and shared utilities\n│   ├── schemas/          # Zod validation schemas\n│   └── constants.ts      # Shared constants (API_URL, CHARACTER_LIMIT, etc.)\n└── dist/                 # Built JavaScript files (entry point: dist/index.js)\n```\n\n## Tool Implementation\n\n### Tool Naming\n\nUse snake_case for tool names (e.g., \"search_users\", \"create_project\", \"get_channel_info\") with clear, action-oriented names.\n\n**Avoid Naming Conflicts**: Include the service context to prevent overlaps:\n- Use \"slack_send_message\" instead of just \"send_message\"\n- Use \"github_create_issue\" instead of just \"create_issue\"\n- Use \"asana_list_tasks\" instead of just \"list_tasks\"\n\n### Tool Structure\n\nTools are registered using the `registerTool` method with the following requirements:\n- Use Zod schemas for runtime input validation and type safety\n- The `description` field must be explicitly provided - JSDoc comments are NOT automatically extracted\n- Explicitly provide `title`, `description`, `inputSchema`, and `annotations`\n- The `inputSchema` must be a Zod schema object (not a JSON schema)\n- Type all parameters and return values explicitly\n\n```typescript\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\n\nconst server = new McpServer({\n  name: \"example-mcp\",\n  version: \"1.0.0\"\n});\n\n// Zod schema for input validation\nconst UserSearchInputSchema = z.object({\n  query: z.string()\n    .min(2, \"Query must be at least 2 characters\")\n    .max(200, \"Query must not exceed 200 characters\")\n    .describe(\"Search string to match against names/emails\"),\n  limit: z.number()\n    .int()\n    .min(1)\n    .max(100)\n    .default(20)\n    .describe(\"Maximum results to return\"),\n  offset: z.number()\n    .int()\n    .min(0)\n    .default(0)\n    .describe(\"Number of results to skip for pagination\"),\n  response_format: z.nativeEnum(ResponseFormat)\n    .default(ResponseFormat.MARKDOWN)\n    .describe(\"Output format: 'markdown' for human-readable or 'json' for machine-readable\")\n}).strict();\n\n// Type definition from Zod schema\ntype UserSearchInput = z.infer<typeof UserSearchInputSchema>;\n\nserver.registerTool(\n  \"example_search_users\",\n  {\n    title: \"Search Example Users\",\n    description: `Search for users in the Example system by name, email, or team.\n\nThis tool searches across all user profiles in the Example platform, supporting partial matches and various search filters. It does NOT create or modify users, only searches existing ones.\n\nArgs:\n  - query (string): Search string to match against names/emails\n  - limit (number): Maximum results to return, between 1-100 (default: 20)\n  - offset (number): Number of results to skip for pagination (default: 0)\n  - response_format ('markdown' | 'json'): Output format (default: 'markdown')\n\nReturns:\n  For JSON format: Structured data with schema:\n  {\n    \"total\": number,           // Total number of matches found\n    \"count\": number,           // Number of results in this response\n    \"offset\": number,          // Current pagination offset\n    \"users\": [\n      {\n        \"id\": string,          // User ID (e.g., \"U123456789\")\n        \"name\": string,        // Full name (e.g., \"John Doe\")\n        \"email\": string,       // Email address\n        \"team\": string,        // Team name (optional)\n        \"active\": boolean      // Whether user is active\n      }\n    ],\n    \"has_more\": boolean,       // Whether more results are available\n    \"next_offset\": number      // Offset for next page (if has_more is true)\n  }\n\nExamples:\n  - Use when: \"Find all marketing team members\" -> params with query=\"team:marketing\"\n  - Use when: \"Search for John's account\" -> params with query=\"john\"\n  - Don't use when: You need to create a user (use example_create_user instead)\n\nError Handling:\n  - Returns \"Error: Rate limit exceeded\" if too many requests (429 status)\n  - Returns \"No users found matching '<query>'\" if search returns empty`,\n    inputSchema: UserSearchInputSchema,\n    annotations: {\n      readOnlyHint: true,\n      destructiveHint: false,\n      idempotentHint: true,\n      openWorldHint: true\n    }\n  },\n  async (params: UserSearchInput) => {\n    try {\n      // Input validation is handled by Zod schema\n      // Make API request using validated parameters\n      const data = await makeApiRequest<any>(\n        \"users/search\",\n        \"GET\",\n        undefined,\n        {\n          q: params.query,\n          limit: params.limit,\n          offset: params.offset\n        }\n      );\n\n      const users = data.users || [];\n      const total = data.total || 0;\n\n      if (!users.length) {\n        return {\n          content: [{\n            type: \"text\",\n            text: `No users found matching '${params.query}'`\n          }]\n        };\n      }\n\n      // Prepare structured output\n      const output = {\n        total,\n        count: users.length,\n        offset: params.offset,\n        users: users.map((user: any) => ({\n          id: user.id,\n          name: user.name,\n          email: user.email,\n          ...(user.team ? { team: user.team } : {}),\n          active: user.active ?? true\n        })),\n        has_more: total > params.offset + users.length,\n        ...(total > params.offset + users.length ? {\n          next_offset: params.offset + users.length\n        } : {})\n      };\n\n      // Format text representation based on requested format\n      let textContent: string;\n      if (params.response_format === ResponseFormat.MARKDOWN) {\n        const lines = [`# User Search Results: '${params.query}'`, \"\",\n          `Found ${total} users (showing ${users.length})`, \"\"];\n        for (const user of users) {\n          lines.push(`## ${user.name} (${user.id})`);\n          lines.push(`- **Email**: ${user.email}`);\n          if (user.team) lines.push(`- **Team**: ${user.team}`);\n          lines.push(\"\");\n        }\n        textContent = lines.join(\"\\n\");\n      } else {\n        textContent = JSON.stringify(output, null, 2);\n      }\n\n      return {\n        content: [{ type: \"text\", text: textContent }],\n        structuredContent: output // Modern pattern for structured data\n      };\n    } catch (error) {\n      return {\n        content: [{\n          type: \"text\",\n          text: handleApiError(error)\n        }]\n      };\n    }\n  }\n);\n```\n\n## Zod Schemas for Input Validation\n\nZod provides runtime type validation:\n\n```typescript\nimport { z } from \"zod\";\n\n// Basic schema with validation\nconst CreateUserSchema = z.object({\n  name: z.string()\n    .min(1, \"Name is required\")\n    .max(100, \"Name must not exceed 100 characters\"),\n  email: z.string()\n    .email(\"Invalid email format\"),\n  age: z.number()\n    .int(\"Age must be a whole number\")\n    .min(0, \"Age cannot be negative\")\n    .max(150, \"Age cannot be greater than 150\")\n}).strict();  // Use .strict() to forbid extra fields\n\n// Enums\nenum ResponseFormat {\n  MARKDOWN = \"markdown\",\n  JSON = \"json\"\n}\n\nconst SearchSchema = z.object({\n  response_format: z.nativeEnum(ResponseFormat)\n    .default(ResponseFormat.MARKDOWN)\n    .describe(\"Output format\")\n});\n\n// Optional fields with defaults\nconst PaginationSchema = z.object({\n  limit: z.number()\n    .int()\n    .min(1)\n    .max(100)\n    .default(20)\n    .describe(\"Maximum results to return\"),\n  offset: z.number()\n    .int()\n    .min(0)\n    .default(0)\n    .describe(\"Number of results to skip\")\n});\n```\n\n## Response Format Options\n\nSupport multiple output formats for flexibility:\n\n```typescript\nenum ResponseFormat {\n  MARKDOWN = \"markdown\",\n  JSON = \"json\"\n}\n\nconst inputSchema = z.object({\n  query: z.string(),\n  response_format: z.nativeEnum(ResponseFormat)\n    .default(ResponseFormat.MARKDOWN)\n    .describe(\"Output format: 'markdown' for human-readable or 'json' for machine-readable\")\n});\n```\n\n**Markdown format**:\n- Use headers, lists, and formatting for clarity\n- Convert timestamps to human-readable format\n- Show display names with IDs in parentheses\n- Omit verbose metadata\n- Group related information logically\n\n**JSON format**:\n- Return complete, structured data suitable for programmatic processing\n- Include all available fields and metadata\n- Use consistent field names and types\n\n## Pagination Implementation\n\nFor tools that list resources:\n\n```typescript\nconst ListSchema = z.object({\n  limit: z.number().int().min(1).max(100).default(20),\n  offset: z.number().int().min(0).default(0)\n});\n\nasync function listItems(params: z.infer<typeof ListSchema>) {\n  const data = await apiRequest(params.limit, params.offset);\n\n  const response = {\n    total: data.total,\n    count: data.items.length,\n    offset: params.offset,\n    items: data.items,\n    has_more: data.total > params.offset + data.items.length,\n    next_offset: data.total > params.offset + data.items.length\n      ? params.offset + data.items.length\n      : undefined\n  };\n\n  return JSON.stringify(response, null, 2);\n}\n```\n\n## Character Limits and Truncation\n\nAdd a CHARACTER_LIMIT constant to prevent overwhelming responses:\n\n```typescript\n// At module level in constants.ts\nexport const CHARACTER_LIMIT = 25000;  // Maximum response size in characters\n\nasync function searchTool(params: SearchInput) {\n  let result = generateResponse(data);\n\n  // Check character limit and truncate if needed\n  if (result.length > CHARACTER_LIMIT) {\n    const truncatedData = data.slice(0, Math.max(1, data.length / 2));\n    response.data = truncatedData;\n    response.truncated = true;\n    response.truncation_message =\n      `Response truncated from ${data.length} to ${truncatedData.length} items. ` +\n      `Use 'offset' parameter or add filters to see more results.`;\n    result = JSON.stringify(response, null, 2);\n  }\n\n  return result;\n}\n```\n\n## Error Handling\n\nProvide clear, actionable error messages:\n\n```typescript\nimport axios, { AxiosError } from \"axios\";\n\nfunction handleApiError(error: unknown): string {\n  if (error instanceof AxiosError) {\n    if (error.response) {\n      switch (error.response.status) {\n        case 404:\n          return \"Error: Resource not found. Please check the ID is correct.\";\n        case 403:\n          return \"Error: Permission denied. You don't have access to this resource.\";\n        case 429:\n          return \"Error: Rate limit exceeded. Please wait before making more requests.\";\n        default:\n          return `Error: API request failed with status ${error.response.status}`;\n      }\n    } else if (error.code === \"ECONNABORTED\") {\n      return \"Error: Request timed out. Please try again.\";\n    }\n  }\n  return `Error: Unexpected error occurred: ${error instanceof Error ? error.message : String(error)}`;\n}\n```\n\n## Shared Utilities\n\nExtract common functionality into reusable functions:\n\n```typescript\n// Shared API request function\nasync function makeApiRequest<T>(\n  endpoint: string,\n  method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" = \"GET\",\n  data?: any,\n  params?: any\n): Promise<T> {\n  try {\n    const response = await axios({\n      method,\n      url: `${API_BASE_URL}/${endpoint}`,\n      data,\n      params,\n      timeout: 30000,\n      headers: {\n        \"Content-Type\": \"application/json\",\n        \"Accept\": \"application/json\"\n      }\n    });\n    return response.data;\n  } catch (error) {\n    throw error;\n  }\n}\n```\n\n## Async/Await Best Practices\n\nAlways use async/await for network requests and I/O operations:\n\n```typescript\n// Good: Async network request\nasync function fetchData(resourceId: string): Promise<ResourceData> {\n  const response = await axios.get(`${API_URL}/resource/${resourceId}`);\n  return response.data;\n}\n\n// Bad: Promise chains\nfunction fetchData(resourceId: string): Promise<ResourceData> {\n  return axios.get(`${API_URL}/resource/${resourceId}`)\n    .then(response => response.data);  // Harder to read and maintain\n}\n```\n\n## TypeScript Best Practices\n\n1. **Use Strict TypeScript**: Enable strict mode in tsconfig.json\n2. **Define Interfaces**: Create clear interface definitions for all data structures\n3. **Avoid `any`**: Use proper types or `unknown` instead of `any`\n4. **Zod for Runtime Validation**: Use Zod schemas to validate external data\n5. **Type Guards**: Create type guard functions for complex type checking\n6. **Error Handling**: Always use try-catch with proper error type checking\n7. **Null Safety**: Use optional chaining (`?.`) and nullish coalescing (`??`)\n\n```typescript\n// Good: Type-safe with Zod and interfaces\ninterface UserResponse {\n  id: string;\n  name: string;\n  email: string;\n  team?: string;\n  active: boolean;\n}\n\nconst UserSchema = z.object({\n  id: z.string(),\n  name: z.string(),\n  email: z.string().email(),\n  team: z.string().optional(),\n  active: z.boolean()\n});\n\ntype User = z.infer<typeof UserSchema>;\n\nasync function getUser(id: string): Promise<User> {\n  const data = await apiCall(`/users/${id}`);\n  return UserSchema.parse(data);  // Runtime validation\n}\n\n// Bad: Using any\nasync function getUser(id: string): Promise<any> {\n  return await apiCall(`/users/${id}`);  // No type safety\n}\n```\n\n## Package Configuration\n\n### package.json\n\n```json\n{\n  \"name\": \"{service}-mcp-server\",\n  \"version\": \"1.0.0\",\n  \"description\": \"MCP server for {Service} API integration\",\n  \"type\": \"module\",\n  \"main\": \"dist/index.js\",\n  \"scripts\": {\n    \"start\": \"node dist/index.js\",\n    \"dev\": \"tsx watch src/index.ts\",\n    \"build\": \"tsc\",\n    \"clean\": \"rm -rf dist\"\n  },\n  \"engines\": {\n    \"node\": \">=18\"\n  },\n  \"dependencies\": {\n    \"@modelcontextprotocol/sdk\": \"^1.6.1\",\n    \"axios\": \"^1.7.9\",\n    \"zod\": \"^3.23.8\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.10.0\",\n    \"tsx\": \"^4.19.2\",\n    \"typescript\": \"^5.7.2\"\n  }\n}\n```\n\n### tsconfig.json\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"Node16\",\n    \"moduleResolution\": \"Node16\",\n    \"lib\": [\"ES2022\"],\n    \"outDir\": \"./dist\",\n    \"rootDir\": \"./src\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"declaration\": true,\n    \"declarationMap\": true,\n    \"sourceMap\": true,\n    \"allowSyntheticDefaultImports\": true\n  },\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"node_modules\", \"dist\"]\n}\n```\n\n## Complete Example\n\n```typescript\n#!/usr/bin/env node\n/**\n * MCP Server for Example Service.\n *\n * This server provides tools to interact with Example API, including user search,\n * project management, and data export capabilities.\n */\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport axios, { AxiosError } from \"axios\";\n\n// Constants\nconst API_BASE_URL = \"https://api.example.com/v1\";\nconst CHARACTER_LIMIT = 25000;\n\n// Enums\nenum ResponseFormat {\n  MARKDOWN = \"markdown\",\n  JSON = \"json\"\n}\n\n// Zod schemas\nconst UserSearchInputSchema = z.object({\n  query: z.string()\n    .min(2, \"Query must be at least 2 characters\")\n    .max(200, \"Query must not exceed 200 characters\")\n    .describe(\"Search string to match against names/emails\"),\n  limit: z.number()\n    .int()\n    .min(1)\n    .max(100)\n    .default(20)\n    .describe(\"Maximum results to return\"),\n  offset: z.number()\n    .int()\n    .min(0)\n    .default(0)\n    .describe(\"Number of results to skip for pagination\"),\n  response_format: z.nativeEnum(ResponseFormat)\n    .default(ResponseFormat.MARKDOWN)\n    .describe(\"Output format: 'markdown' for human-readable or 'json' for machine-readable\")\n}).strict();\n\ntype UserSearchInput = z.infer<typeof UserSearchInputSchema>;\n\n// Shared utility functions\nasync function makeApiRequest<T>(\n  endpoint: string,\n  method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" = \"GET\",\n  data?: any,\n  params?: any\n): Promise<T> {\n  try {\n    const response = await axios({\n      method,\n      url: `${API_BASE_URL}/${endpoint}`,\n      data,\n      params,\n      timeout: 30000,\n      headers: {\n        \"Content-Type\": \"application/json\",\n        \"Accept\": \"application/json\"\n      }\n    });\n    return response.data;\n  } catch (error) {\n    throw error;\n  }\n}\n\nfunction handleApiError(error: unknown): string {\n  if (error instanceof AxiosError) {\n    if (error.response) {\n      switch (error.response.status) {\n        case 404:\n          return \"Error: Resource not found. Please check the ID is correct.\";\n        case 403:\n          return \"Error: Permission denied. You don't have access to this resource.\";\n        case 429:\n          return \"Error: Rate limit exceeded. Please wait before making more requests.\";\n        default:\n          return `Error: API request failed with status ${error.response.status}`;\n      }\n    } else if (error.code === \"ECONNABORTED\") {\n      return \"Error: Request timed out. Please try again.\";\n    }\n  }\n  return `Error: Unexpected error occurred: ${error instanceof Error ? error.message : String(error)}`;\n}\n\n// Create MCP server instance\nconst server = new McpServer({\n  name: \"example-mcp\",\n  version: \"1.0.0\"\n});\n\n// Register tools\nserver.registerTool(\n  \"example_search_users\",\n  {\n    title: \"Search Example Users\",\n    description: `[Full description as shown above]`,\n    inputSchema: UserSearchInputSchema,\n    annotations: {\n      readOnlyHint: true,\n      destructiveHint: false,\n      idempotentHint: true,\n      openWorldHint: true\n    }\n  },\n  async (params: UserSearchInput) => {\n    // Implementation as shown above\n  }\n);\n\n// Main function\n// For stdio (local):\nasync function runStdio() {\n  if (!process.env.EXAMPLE_API_KEY) {\n    console.error(\"ERROR: EXAMPLE_API_KEY environment variable is required\");\n    process.exit(1);\n  }\n\n  const transport = new StdioServerTransport();\n  await server.connect(transport);\n  console.error(\"MCP server running via stdio\");\n}\n\n// For streamable HTTP (remote):\nasync function runHTTP() {\n  if (!process.env.EXAMPLE_API_KEY) {\n    console.error(\"ERROR: EXAMPLE_API_KEY environment variable is required\");\n    process.exit(1);\n  }\n\n  const app = express();\n  app.use(express.json());\n\n  app.post('/mcp', async (req, res) => {\n    const transport = new StreamableHTTPServerTransport({\n      sessionIdGenerator: undefined,\n      enableJsonResponse: true\n    });\n    res.on('close', () => transport.close());\n    await server.connect(transport);\n    await transport.handleRequest(req, res, req.body);\n  });\n\n  const port = parseInt(process.env.PORT || '3000');\n  app.listen(port, () => {\n    console.error(`MCP server running on http://localhost:${port}/mcp`);\n  });\n}\n\n// Choose transport based on environment\nconst transport = process.env.TRANSPORT || 'stdio';\nif (transport === 'http') {\n  runHTTP().catch(error => {\n    console.error(\"Server error:\", error);\n    process.exit(1);\n  });\n} else {\n  runStdio().catch(error => {\n    console.error(\"Server error:\", error);\n    process.exit(1);\n  });\n}\n```\n\n---\n\n## Advanced MCP Features\n\n### Resource Registration\n\nExpose data as resources for efficient, URI-based access:\n\n```typescript\nimport { ResourceTemplate } from \"@modelcontextprotocol/sdk/types.js\";\n\n// Register a resource with URI template\nserver.registerResource(\n  {\n    uri: \"file://documents/{name}\",\n    name: \"Document Resource\",\n    description: \"Access documents by name\",\n    mimeType: \"text/plain\"\n  },\n  async (uri: string) => {\n    // Extract parameter from URI\n    const match = uri.match(/^file:\\/\\/documents\\/(.+)$/);\n    if (!match) {\n      throw new Error(\"Invalid URI format\");\n    }\n\n    const documentName = match[1];\n    const content = await loadDocument(documentName);\n\n    return {\n      contents: [{\n        uri,\n        mimeType: \"text/plain\",\n        text: content\n      }]\n    };\n  }\n);\n\n// List available resources dynamically\nserver.registerResourceList(async () => {\n  const documents = await getAvailableDocuments();\n  return {\n    resources: documents.map(doc => ({\n      uri: `file://documents/${doc.name}`,\n      name: doc.name,\n      mimeType: \"text/plain\",\n      description: doc.description\n    }))\n  };\n});\n```\n\n**When to use Resources vs Tools:**\n- **Resources**: For data access with simple URI-based parameters\n- **Tools**: For complex operations requiring validation and business logic\n- **Resources**: When data is relatively static or template-based\n- **Tools**: When operations have side effects or complex workflows\n\n### Transport Options\n\nThe TypeScript SDK supports two main transport mechanisms:\n\n#### Streamable HTTP (Recommended for Remote Servers)\n\n```typescript\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport express from \"express\";\n\nconst app = express();\napp.use(express.json());\n\napp.post('/mcp', async (req, res) => {\n  // Create new transport for each request (stateless, prevents request ID collisions)\n  const transport = new StreamableHTTPServerTransport({\n    sessionIdGenerator: undefined,\n    enableJsonResponse: true\n  });\n\n  res.on('close', () => transport.close());\n\n  await server.connect(transport);\n  await transport.handleRequest(req, res, req.body);\n});\n\napp.listen(3000);\n```\n\n#### stdio (For Local Integrations)\n\n```typescript\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n```\n\n**Transport selection:**\n- **Streamable HTTP**: Web services, remote access, multiple clients\n- **stdio**: Command-line tools, local development, subprocess integration\n\n### Notification Support\n\nNotify clients when server state changes:\n\n```typescript\n// Notify when tools list changes\nserver.notification({\n  method: \"notifications/tools/list_changed\"\n});\n\n// Notify when resources change\nserver.notification({\n  method: \"notifications/resources/list_changed\"\n});\n```\n\nUse notifications sparingly - only when server capabilities genuinely change.\n\n---\n\n## Code Best Practices\n\n### Code Composability and Reusability\n\nYour implementation MUST prioritize composability and code reuse:\n\n1. **Extract Common Functionality**:\n   - Create reusable helper functions for operations used across multiple tools\n   - Build shared API clients for HTTP requests instead of duplicating code\n   - Centralize error handling logic in utility functions\n   - Extract business logic into dedicated functions that can be composed\n   - Extract shared markdown or JSON field selection & formatting functionality\n\n2. **Avoid Duplication**:\n   - NEVER copy-paste similar code between tools\n   - If you find yourself writing similar logic twice, extract it into a function\n   - Common operations like pagination, filtering, field selection, and formatting should be shared\n   - Authentication/authorization logic should be centralized\n\n## Building and Running\n\nAlways build your TypeScript code before running:\n\n```bash\n# Build the project\nnpm run build\n\n# Run the server\nnpm start\n\n# Development with auto-reload\nnpm run dev\n```\n\nAlways ensure `npm run build` completes successfully before considering the implementation complete.\n\n## Quality Checklist\n\nBefore finalizing your Node/TypeScript MCP server implementation, ensure:\n\n### Strategic Design\n- [ ] Tools enable complete workflows, not just API endpoint wrappers\n- [ ] Tool names reflect natural task subdivisions\n- [ ] Response formats optimize for agent context efficiency\n- [ ] Human-readable identifiers used where appropriate\n- [ ] Error messages guide agents toward correct usage\n\n### Implementation Quality\n- [ ] FOCUSED IMPLEMENTATION: Most important and valuable tools implemented\n- [ ] All tools registered using `registerTool` with complete configuration\n- [ ] All tools include `title`, `description`, `inputSchema`, and `annotations`\n- [ ] Annotations correctly set (readOnlyHint, destructiveHint, idempotentHint, openWorldHint)\n- [ ] All tools use Zod schemas for runtime input validation with `.strict()` enforcement\n- [ ] All Zod schemas have proper constraints and descriptive error messages\n- [ ] All tools have comprehensive descriptions with explicit input/output types\n- [ ] Descriptions include return value examples and complete schema documentation\n- [ ] Error messages are clear, actionable, and educational\n\n### TypeScript Quality\n- [ ] TypeScript interfaces are defined for all data structures\n- [ ] Strict TypeScript is enabled in tsconfig.json\n- [ ] No use of `any` type - use `unknown` or proper types instead\n- [ ] All async functions have explicit Promise<T> return types\n- [ ] Error handling uses proper type guards (e.g., `axios.isAxiosError`, `z.ZodError`)\n\n### Advanced Features (where applicable)\n- [ ] Resources registered for appropriate data endpoints\n- [ ] Appropriate transport configured (stdio or streamable HTTP)\n- [ ] Notifications implemented for dynamic server capabilities\n- [ ] Type-safe with SDK interfaces\n\n### Project Configuration\n- [ ] Package.json includes all necessary dependencies\n- [ ] Build script produces working JavaScript in dist/ directory\n- [ ] Main entry point is properly configured as dist/index.js\n- [ ] Server name follows format: `{service}-mcp-server`\n- [ ] tsconfig.json properly configured with strict mode\n\n### Code Quality\n- [ ] Pagination is properly implemented where applicable\n- [ ] Large responses check CHARACTER_LIMIT constant and truncate with clear messages\n- [ ] Filtering options are provided for potentially large result sets\n- [ ] All network operations handle timeouts and connection errors gracefully\n- [ ] Common functionality is extracted into reusable functions\n- [ ] Return types are consistent across similar operations\n\n### Testing and Build\n- [ ] `npm run build` completes successfully without errors\n- [ ] dist/index.js created and executable\n- [ ] Server runs: `node dist/index.js --help`\n- [ ] All imports resolve correctly\n- [ ] Sample tool calls work as expected\n","isInternal":false,"tokens":6582,"sizeBytes":28551},{"name":"python_mcp_server.md","path":"core/skills/builtin/mcp-builder/reference/python_mcp_server.md","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/mcp-builder/reference/python_mcp_server.md","title":"Reference Skill","category":"anthropic-skill","format":"markdown","content":"# Python MCP Server Implementation Guide\n\n## Overview\n\nThis document provides Python-specific best practices and examples for implementing MCP servers using the MCP Python SDK. It covers server setup, tool registration patterns, input validation with Pydantic, error handling, and complete working examples.\n\n---\n\n## Quick Reference\n\n### Key Imports\n```python\nfrom mcp.server.fastmcp import FastMCP\nfrom pydantic import BaseModel, Field, field_validator, ConfigDict\nfrom typing import Optional, List, Dict, Any\nfrom enum import Enum\nimport httpx\n```\n\n### Server Initialization\n```python\nmcp = FastMCP(\"service_mcp\")\n```\n\n### Tool Registration Pattern\n```python\n@mcp.tool(name=\"tool_name\", annotations={...})\nasync def tool_function(params: InputModel) -> str:\n    # Implementation\n    pass\n```\n\n---\n\n## MCP Python SDK and FastMCP\n\nThe official MCP Python SDK provides FastMCP, a high-level framework for building MCP servers. It provides:\n- Automatic description and inputSchema generation from function signatures and docstrings\n- Pydantic model integration for input validation\n- Decorator-based tool registration with `@mcp.tool`\n\n**For complete SDK documentation, use WebFetch to load:**\n`https://raw.githubusercontent.com/modelcontextprotocol/python-sdk/main/README.md`\n\n## Server Naming Convention\n\nPython MCP servers must follow this naming pattern:\n- **Format**: `{service}_mcp` (lowercase with underscores)\n- **Examples**: `github_mcp`, `jira_mcp`, `stripe_mcp`\n\nThe name should be:\n- General (not tied to specific features)\n- Descriptive of the service/API being integrated\n- Easy to infer from the task description\n- Without version numbers or dates\n\n## Tool Implementation\n\n### Tool Naming\n\nUse snake_case for tool names (e.g., \"search_users\", \"create_project\", \"get_channel_info\") with clear, action-oriented names.\n\n**Avoid Naming Conflicts**: Include the service context to prevent overlaps:\n- Use \"slack_send_message\" instead of just \"send_message\"\n- Use \"github_create_issue\" instead of just \"create_issue\"\n- Use \"asana_list_tasks\" instead of just \"list_tasks\"\n\n### Tool Structure with FastMCP\n\nTools are defined using the `@mcp.tool` decorator with Pydantic models for input validation:\n\n```python\nfrom pydantic import BaseModel, Field, ConfigDict\nfrom mcp.server.fastmcp import FastMCP\n\n# Initialize the MCP server\nmcp = FastMCP(\"example_mcp\")\n\n# Define Pydantic model for input validation\nclass ServiceToolInput(BaseModel):\n    '''Input model for service tool operation.'''\n    model_config = ConfigDict(\n        str_strip_whitespace=True,  # Auto-strip whitespace from strings\n        validate_assignment=True,    # Validate on assignment\n        extra='forbid'              # Forbid extra fields\n    )\n\n    param1: str = Field(..., description=\"First parameter description (e.g., 'user123', 'project-abc')\", min_length=1, max_length=100)\n    param2: Optional[int] = Field(default=None, description=\"Optional integer parameter with constraints\", ge=0, le=1000)\n    tags: Optional[List[str]] = Field(default_factory=list, description=\"List of tags to apply\", max_items=10)\n\n@mcp.tool(\n    name=\"service_tool_name\",\n    annotations={\n        \"title\": \"Human-Readable Tool Title\",\n        \"readOnlyHint\": True,     # Tool does not modify environment\n        \"destructiveHint\": False,  # Tool does not perform destructive operations\n        \"idempotentHint\": True,    # Repeated calls have no additional effect\n        \"openWorldHint\": False     # Tool does not interact with external entities\n    }\n)\nasync def service_tool_name(params: ServiceToolInput) -> str:\n    '''Tool description automatically becomes the 'description' field.\n\n    This tool performs a specific operation on the service. It validates all inputs\n    using the ServiceToolInput Pydantic model before processing.\n\n    Args:\n        params (ServiceToolInput): Validated input parameters containing:\n            - param1 (str): First parameter description\n            - param2 (Optional[int]): Optional parameter with default\n            - tags (Optional[List[str]]): List of tags\n\n    Returns:\n        str: JSON-formatted response containing operation results\n    '''\n    # Implementation here\n    pass\n```\n\n## Pydantic v2 Key Features\n\n- Use `model_config` instead of nested `Config` class\n- Use `field_validator` instead of deprecated `validator`\n- Use `model_dump()` instead of deprecated `dict()`\n- Validators require `@classmethod` decorator\n- Type hints are required for validator methods\n\n```python\nfrom pydantic import BaseModel, Field, field_validator, ConfigDict\n\nclass CreateUserInput(BaseModel):\n    model_config = ConfigDict(\n        str_strip_whitespace=True,\n        validate_assignment=True\n    )\n\n    name: str = Field(..., description=\"User's full name\", min_length=1, max_length=100)\n    email: str = Field(..., description=\"User's email address\", pattern=r'^[\\w\\.-]+@[\\w\\.-]+\\.\\w+$')\n    age: int = Field(..., description=\"User's age\", ge=0, le=150)\n\n    @field_validator('email')\n    @classmethod\n    def validate_email(cls, v: str) -> str:\n        if not v.strip():\n            raise ValueError(\"Email cannot be empty\")\n        return v.lower()\n```\n\n## Response Format Options\n\nSupport multiple output formats for flexibility:\n\n```python\nfrom enum import Enum\n\nclass ResponseFormat(str, Enum):\n    '''Output format for tool responses.'''\n    MARKDOWN = \"markdown\"\n    JSON = \"json\"\n\nclass UserSearchInput(BaseModel):\n    query: str = Field(..., description=\"Search query\")\n    response_format: ResponseFormat = Field(\n        default=ResponseFormat.MARKDOWN,\n        description=\"Output format: 'markdown' for human-readable or 'json' for machine-readable\"\n    )\n```\n\n**Markdown format**:\n- Use headers, lists, and formatting for clarity\n- Convert timestamps to human-readable format (e.g., \"2024-01-15 10:30:00 UTC\" instead of epoch)\n- Show display names with IDs in parentheses (e.g., \"@john.doe (U123456)\")\n- Omit verbose metadata (e.g., show only one profile image URL, not all sizes)\n- Group related information logically\n\n**JSON format**:\n- Return complete, structured data suitable for programmatic processing\n- Include all available fields and metadata\n- Use consistent field names and types\n\n## Pagination Implementation\n\nFor tools that list resources:\n\n```python\nclass ListInput(BaseModel):\n    limit: Optional[int] = Field(default=20, description=\"Maximum results to return\", ge=1, le=100)\n    offset: Optional[int] = Field(default=0, description=\"Number of results to skip for pagination\", ge=0)\n\nasync def list_items(params: ListInput) -> str:\n    # Make API request with pagination\n    data = await api_request(limit=params.limit, offset=params.offset)\n\n    # Return pagination info\n    response = {\n        \"total\": data[\"total\"],\n        \"count\": len(data[\"items\"]),\n        \"offset\": params.offset,\n        \"items\": data[\"items\"],\n        \"has_more\": data[\"total\"] > params.offset + len(data[\"items\"]),\n        \"next_offset\": params.offset + len(data[\"items\"]) if data[\"total\"] > params.offset + len(data[\"items\"]) else None\n    }\n    return json.dumps(response, indent=2)\n```\n\n## Error Handling\n\nProvide clear, actionable error messages:\n\n```python\ndef _handle_api_error(e: Exception) -> str:\n    '''Consistent error formatting across all tools.'''\n    if isinstance(e, httpx.HTTPStatusError):\n        if e.response.status_code == 404:\n            return \"Error: Resource not found. Please check the ID is correct.\"\n        elif e.response.status_code == 403:\n            return \"Error: Permission denied. You don't have access to this resource.\"\n        elif e.response.status_code == 429:\n            return \"Error: Rate limit exceeded. Please wait before making more requests.\"\n        return f\"Error: API request failed with status {e.response.status_code}\"\n    elif isinstance(e, httpx.TimeoutException):\n        return \"Error: Request timed out. Please try again.\"\n    return f\"Error: Unexpected error occurred: {type(e).__name__}\"\n```\n\n## Shared Utilities\n\nExtract common functionality into reusable functions:\n\n```python\n# Shared API request function\nasync def _make_api_request(endpoint: str, method: str = \"GET\", **kwargs) -> dict:\n    '''Reusable function for all API calls.'''\n    async with httpx.AsyncClient() as client:\n        response = await client.request(\n            method,\n            f\"{API_BASE_URL}/{endpoint}\",\n            timeout=30.0,\n            **kwargs\n        )\n        response.raise_for_status()\n        return response.json()\n```\n\n## Async/Await Best Practices\n\nAlways use async/await for network requests and I/O operations:\n\n```python\n# Good: Async network request\nasync def fetch_data(resource_id: str) -> dict:\n    async with httpx.AsyncClient() as client:\n        response = await client.get(f\"{API_URL}/resource/{resource_id}\")\n        response.raise_for_status()\n        return response.json()\n\n# Bad: Synchronous request\ndef fetch_data(resource_id: str) -> dict:\n    response = requests.get(f\"{API_URL}/resource/{resource_id}\")  # Blocks\n    return response.json()\n```\n\n## Type Hints\n\nUse type hints throughout:\n\n```python\nfrom typing import Optional, List, Dict, Any\n\nasync def get_user(user_id: str) -> Dict[str, Any]:\n    data = await fetch_user(user_id)\n    return {\"id\": data[\"id\"], \"name\": data[\"name\"]}\n```\n\n## Tool Docstrings\n\nEvery tool must have comprehensive docstrings with explicit type information:\n\n```python\nasync def search_users(params: UserSearchInput) -> str:\n    '''\n    Search for users in the Example system by name, email, or team.\n\n    This tool searches across all user profiles in the Example platform,\n    supporting partial matches and various search filters. It does NOT\n    create or modify users, only searches existing ones.\n\n    Args:\n        params (UserSearchInput): Validated input parameters containing:\n            - query (str): Search string to match against names/emails (e.g., \"john\", \"@example.com\", \"team:marketing\")\n            - limit (Optional[int]): Maximum results to return, between 1-100 (default: 20)\n            - offset (Optional[int]): Number of results to skip for pagination (default: 0)\n\n    Returns:\n        str: JSON-formatted string containing search results with the following schema:\n\n        Success response:\n        {\n            \"total\": int,           # Total number of matches found\n            \"count\": int,           # Number of results in this response\n            \"offset\": int,          # Current pagination offset\n            \"users\": [\n                {\n                    \"id\": str,      # User ID (e.g., \"U123456789\")\n                    \"name\": str,    # Full name (e.g., \"John Doe\")\n                    \"email\": str,   # Email address (e.g., \"john@example.com\")\n                    \"team\": str     # Team name (e.g., \"Marketing\") - optional\n                }\n            ]\n        }\n\n        Error response:\n        \"Error: <error message>\" or \"No users found matching '<query>'\"\n\n    Examples:\n        - Use when: \"Find all marketing team members\" -> params with query=\"team:marketing\"\n        - Use when: \"Search for John's account\" -> params with query=\"john\"\n        - Don't use when: You need to create a user (use example_create_user instead)\n        - Don't use when: You have a user ID and need full details (use example_get_user instead)\n\n    Error Handling:\n        - Input validation errors are handled by Pydantic model\n        - Returns \"Error: Rate limit exceeded\" if too many requests (429 status)\n        - Returns \"Error: Invalid API authentication\" if API key is invalid (401 status)\n        - Returns formatted list of results or \"No users found matching 'query'\"\n    '''\n```\n\n## Complete Example\n\nSee below for a complete Python MCP server example:\n\n```python\n#!/usr/bin/env python3\n'''\nMCP Server for Example Service.\n\nThis server provides tools to interact with Example API, including user search,\nproject management, and data export capabilities.\n'''\n\nfrom typing import Optional, List, Dict, Any\nfrom enum import Enum\nimport httpx\nfrom pydantic import BaseModel, Field, field_validator, ConfigDict\nfrom mcp.server.fastmcp import FastMCP\n\n# Initialize the MCP server\nmcp = FastMCP(\"example_mcp\")\n\n# Constants\nAPI_BASE_URL = \"https://api.example.com/v1\"\n\n# Enums\nclass ResponseFormat(str, Enum):\n    '''Output format for tool responses.'''\n    MARKDOWN = \"markdown\"\n    JSON = \"json\"\n\n# Pydantic Models for Input Validation\nclass UserSearchInput(BaseModel):\n    '''Input model for user search operations.'''\n    model_config = ConfigDict(\n        str_strip_whitespace=True,\n        validate_assignment=True\n    )\n\n    query: str = Field(..., description=\"Search string to match against names/emails\", min_length=2, max_length=200)\n    limit: Optional[int] = Field(default=20, description=\"Maximum results to return\", ge=1, le=100)\n    offset: Optional[int] = Field(default=0, description=\"Number of results to skip for pagination\", ge=0)\n    response_format: ResponseFormat = Field(default=ResponseFormat.MARKDOWN, description=\"Output format\")\n\n    @field_validator('query')\n    @classmethod\n    def validate_query(cls, v: str) -> str:\n        if not v.strip():\n            raise ValueError(\"Query cannot be empty or whitespace only\")\n        return v.strip()\n\n# Shared utility functions\nasync def _make_api_request(endpoint: str, method: str = \"GET\", **kwargs) -> dict:\n    '''Reusable function for all API calls.'''\n    async with httpx.AsyncClient() as client:\n        response = await client.request(\n            method,\n            f\"{API_BASE_URL}/{endpoint}\",\n            timeout=30.0,\n            **kwargs\n        )\n        response.raise_for_status()\n        return response.json()\n\ndef _handle_api_error(e: Exception) -> str:\n    '''Consistent error formatting across all tools.'''\n    if isinstance(e, httpx.HTTPStatusError):\n        if e.response.status_code == 404:\n            return \"Error: Resource not found. Please check the ID is correct.\"\n        elif e.response.status_code == 403:\n            return \"Error: Permission denied. You don't have access to this resource.\"\n        elif e.response.status_code == 429:\n            return \"Error: Rate limit exceeded. Please wait before making more requests.\"\n        return f\"Error: API request failed with status {e.response.status_code}\"\n    elif isinstance(e, httpx.TimeoutException):\n        return \"Error: Request timed out. Please try again.\"\n    return f\"Error: Unexpected error occurred: {type(e).__name__}\"\n\n# Tool definitions\n@mcp.tool(\n    name=\"example_search_users\",\n    annotations={\n        \"title\": \"Search Example Users\",\n        \"readOnlyHint\": True,\n        \"destructiveHint\": False,\n        \"idempotentHint\": True,\n        \"openWorldHint\": True\n    }\n)\nasync def example_search_users(params: UserSearchInput) -> str:\n    '''Search for users in the Example system by name, email, or team.\n\n    [Full docstring as shown above]\n    '''\n    try:\n        # Make API request using validated parameters\n        data = await _make_api_request(\n            \"users/search\",\n            params={\n                \"q\": params.query,\n                \"limit\": params.limit,\n                \"offset\": params.offset\n            }\n        )\n\n        users = data.get(\"users\", [])\n        total = data.get(\"total\", 0)\n\n        if not users:\n            return f\"No users found matching '{params.query}'\"\n\n        # Format response based on requested format\n        if params.response_format == ResponseFormat.MARKDOWN:\n            lines = [f\"# User Search Results: '{params.query}'\", \"\"]\n            lines.append(f\"Found {total} users (showing {len(users)})\")\n            lines.append(\"\")\n\n            for user in users:\n                lines.append(f\"## {user['name']} ({user['id']})\")\n                lines.append(f\"- **Email**: {user['email']}\")\n                if user.get('team'):\n                    lines.append(f\"- **Team**: {user['team']}\")\n                lines.append(\"\")\n\n            return \"\\n\".join(lines)\n\n        else:\n            # Machine-readable JSON format\n            import json\n            response = {\n                \"total\": total,\n                \"count\": len(users),\n                \"offset\": params.offset,\n                \"users\": users\n            }\n            return json.dumps(response, indent=2)\n\n    except Exception as e:\n        return _handle_api_error(e)\n\nif __name__ == \"__main__\":\n    mcp.run()\n```\n\n---\n\n## Advanced FastMCP Features\n\n### Context Parameter Injection\n\nFastMCP can automatically inject a `Context` parameter into tools for advanced capabilities like logging, progress reporting, resource reading, and user interaction:\n\n```python\nfrom mcp.server.fastmcp import FastMCP, Context\n\nmcp = FastMCP(\"example_mcp\")\n\n@mcp.tool()\nasync def advanced_search(query: str, ctx: Context) -> str:\n    '''Advanced tool with context access for logging and progress.'''\n\n    # Report progress for long operations\n    await ctx.report_progress(0.25, \"Starting search...\")\n\n    # Log information for debugging\n    await ctx.log_info(\"Processing query\", {\"query\": query, \"timestamp\": datetime.now()})\n\n    # Perform search\n    results = await search_api(query)\n    await ctx.report_progress(0.75, \"Formatting results...\")\n\n    # Access server configuration\n    server_name = ctx.fastmcp.name\n\n    return format_results(results)\n\n@mcp.tool()\nasync def interactive_tool(resource_id: str, ctx: Context) -> str:\n    '''Tool that can request additional input from users.'''\n\n    # Request sensitive information when needed\n    api_key = await ctx.elicit(\n        prompt=\"Please provide your API key:\",\n        input_type=\"password\"\n    )\n\n    # Use the provided key\n    return await api_call(resource_id, api_key)\n```\n\n**Context capabilities:**\n- `ctx.report_progress(progress, message)` - Report progress for long operations\n- `ctx.log_info(message, data)` / `ctx.log_error()` / `ctx.log_debug()` - Logging\n- `ctx.elicit(prompt, input_type)` - Request input from users\n- `ctx.fastmcp.name` - Access server configuration\n- `ctx.read_resource(uri)` - Read MCP resources\n\n### Resource Registration\n\nExpose data as resources for efficient, template-based access:\n\n```python\n@mcp.resource(\"file://documents/{name}\")\nasync def get_document(name: str) -> str:\n    '''Expose documents as MCP resources.\n\n    Resources are useful for static or semi-static data that doesn't\n    require complex parameters. They use URI templates for flexible access.\n    '''\n    document_path = f\"./docs/{name}\"\n    with open(document_path, \"r\") as f:\n        return f.read()\n\n@mcp.resource(\"config://settings/{key}\")\nasync def get_setting(key: str, ctx: Context) -> str:\n    '''Expose configuration as resources with context.'''\n    settings = await load_settings()\n    return json.dumps(settings.get(key, {}))\n```\n\n**When to use Resources vs Tools:**\n- **Resources**: For data access with simple parameters (URI templates)\n- **Tools**: For complex operations with validation and business logic\n\n### Structured Output Types\n\nFastMCP supports multiple return types beyond strings:\n\n```python\nfrom typing import TypedDict\nfrom dataclasses import dataclass\nfrom pydantic import BaseModel\n\n# TypedDict for structured returns\nclass UserData(TypedDict):\n    id: str\n    name: str\n    email: str\n\n@mcp.tool()\nasync def get_user_typed(user_id: str) -> UserData:\n    '''Returns structured data - FastMCP handles serialization.'''\n    return {\"id\": user_id, \"name\": \"John Doe\", \"email\": \"john@example.com\"}\n\n# Pydantic models for complex validation\nclass DetailedUser(BaseModel):\n    id: str\n    name: str\n    email: str\n    created_at: datetime\n    metadata: Dict[str, Any]\n\n@mcp.tool()\nasync def get_user_detailed(user_id: str) -> DetailedUser:\n    '''Returns Pydantic model - automatically generates schema.'''\n    user = await fetch_user(user_id)\n    return DetailedUser(**user)\n```\n\n### Lifespan Management\n\nInitialize resources that persist across requests:\n\n```python\nfrom contextlib import asynccontextmanager\n\n@asynccontextmanager\nasync def app_lifespan():\n    '''Manage resources that live for the server's lifetime.'''\n    # Initialize connections, load config, etc.\n    db = await connect_to_database()\n    config = load_configuration()\n\n    # Make available to all tools\n    yield {\"db\": db, \"config\": config}\n\n    # Cleanup on shutdown\n    await db.close()\n\nmcp = FastMCP(\"example_mcp\", lifespan=app_lifespan)\n\n@mcp.tool()\nasync def query_data(query: str, ctx: Context) -> str:\n    '''Access lifespan resources through context.'''\n    db = ctx.request_context.lifespan_state[\"db\"]\n    results = await db.query(query)\n    return format_results(results)\n```\n\n### Transport Options\n\nFastMCP supports two main transport mechanisms:\n\n```python\n# stdio transport (for local tools) - default\nif __name__ == \"__main__\":\n    mcp.run()\n\n# Streamable HTTP transport (for remote servers)\nif __name__ == \"__main__\":\n    mcp.run(transport=\"streamable_http\", port=8000)\n```\n\n**Transport selection:**\n- **stdio**: Command-line tools, local integrations, subprocess execution\n- **Streamable HTTP**: Web services, remote access, multiple clients\n\n---\n\n## Code Best Practices\n\n### Code Composability and Reusability\n\nYour implementation MUST prioritize composability and code reuse:\n\n1. **Extract Common Functionality**:\n   - Create reusable helper functions for operations used across multiple tools\n   - Build shared API clients for HTTP requests instead of duplicating code\n   - Centralize error handling logic in utility functions\n   - Extract business logic into dedicated functions that can be composed\n   - Extract shared markdown or JSON field selection & formatting functionality\n\n2. **Avoid Duplication**:\n   - NEVER copy-paste similar code between tools\n   - If you find yourself writing similar logic twice, extract it into a function\n   - Common operations like pagination, filtering, field selection, and formatting should be shared\n   - Authentication/authorization logic should be centralized\n\n### Python-Specific Best Practices\n\n1. **Use Type Hints**: Always include type annotations for function parameters and return values\n2. **Pydantic Models**: Define clear Pydantic models for all input validation\n3. **Avoid Manual Validation**: Let Pydantic handle input validation with constraints\n4. **Proper Imports**: Group imports (standard library, third-party, local)\n5. **Error Handling**: Use specific exception types (httpx.HTTPStatusError, not generic Exception)\n6. **Async Context Managers**: Use `async with` for resources that need cleanup\n7. **Constants**: Define module-level constants in UPPER_CASE\n\n## Quality Checklist\n\nBefore finalizing your Python MCP server implementation, ensure:\n\n### Strategic Design\n- [ ] Tools enable complete workflows, not just API endpoint wrappers\n- [ ] Tool names reflect natural task subdivisions\n- [ ] Response formats optimize for agent context efficiency\n- [ ] Human-readable identifiers used where appropriate\n- [ ] Error messages guide agents toward correct usage\n\n### Implementation Quality\n- [ ] FOCUSED IMPLEMENTATION: Most important and valuable tools implemented\n- [ ] All tools have descriptive names and documentation\n- [ ] Return types are consistent across similar operations\n- [ ] Error handling is implemented for all external calls\n- [ ] Server name follows format: `{service}_mcp`\n- [ ] All network operations use async/await\n- [ ] Common functionality is extracted into reusable functions\n- [ ] Error messages are clear, actionable, and educational\n- [ ] Outputs are properly validated and formatted\n\n### Tool Configuration\n- [ ] All tools implement 'name' and 'annotations' in the decorator\n- [ ] Annotations correctly set (readOnlyHint, destructiveHint, idempotentHint, openWorldHint)\n- [ ] All tools use Pydantic BaseModel for input validation with Field() definitions\n- [ ] All Pydantic Fields have explicit types and descriptions with constraints\n- [ ] All tools have comprehensive docstrings with explicit input/output types\n- [ ] Docstrings include complete schema structure for dict/JSON returns\n- [ ] Pydantic models handle input validation (no manual validation needed)\n\n### Advanced Features (where applicable)\n- [ ] Context injection used for logging, progress, or elicitation\n- [ ] Resources registered for appropriate data endpoints\n- [ ] Lifespan management implemented for persistent connections\n- [ ] Structured output types used (TypedDict, Pydantic models)\n- [ ] Appropriate transport configured (stdio or streamable HTTP)\n\n### Code Quality\n- [ ] File includes proper imports including Pydantic imports\n- [ ] Pagination is properly implemented where applicable\n- [ ] Filtering options are provided for potentially large result sets\n- [ ] All async functions are properly defined with `async def`\n- [ ] HTTP client usage follows async patterns with proper context managers\n- [ ] Type hints are used throughout the code\n- [ ] Constants are defined at module level in UPPER_CASE\n\n### Testing\n- [ ] Server runs successfully: `python your_server.py --help`\n- [ ] All imports resolve correctly\n- [ ] Sample tool calls work as expected\n- [ ] Error scenarios handled gracefully\n","isInternal":false,"tokens":5525,"sizeBytes":25100},{"name":"SKILL.md","path":"core/skills/builtin/mcp-builder/SKILL.md","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/mcp-builder/SKILL.md","title":"mcp-builder","category":"anthropic-skill","format":"markdown","content":"---\nname: mcp-builder\ndescription: Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).\nlicense: Complete terms in LICENSE.txt\n---\n\n# MCP Server Development Guide\n\n## Overview\n\nCreate MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. The quality of an MCP server is measured by how well it enables LLMs to accomplish real-world tasks.\n\n---\n\n# Process\n\n## 🚀 High-Level Workflow\n\nCreating a high-quality MCP server involves four main phases:\n\n### Phase 1: Deep Research and Planning\n\n#### 1.1 Understand Modern MCP Design\n\n**API Coverage vs. Workflow Tools:**\nBalance comprehensive API endpoint coverage with specialized workflow tools. Workflow tools can be more convenient for specific tasks, while comprehensive coverage gives agents flexibility to compose operations. Performance varies by client—some clients benefit from code execution that combines basic tools, while others work better with higher-level workflows. When uncertain, prioritize comprehensive API coverage.\n\n**Tool Naming and Discoverability:**\nClear, descriptive tool names help agents find the right tools quickly. Use consistent prefixes (e.g., `github_create_issue`, `github_list_repos`) and action-oriented naming.\n\n**Context Management:**\nAgents benefit from concise tool descriptions and the ability to filter/paginate results. Design tools that return focused, relevant data. Some clients support code execution which can help agents filter and process data efficiently.\n\n**Actionable Error Messages:**\nError messages should guide agents toward solutions with specific suggestions and next steps.\n\n#### 1.2 Study MCP Protocol Documentation\n\n**Navigate the MCP specification:**\n\nStart with the sitemap to find relevant pages: `https://modelcontextprotocol.io/sitemap.xml`\n\nThen fetch specific pages with `.md` suffix for markdown format (e.g., `https://modelcontextprotocol.io/specification/draft.md`).\n\nKey pages to review:\n- Specification overview and architecture\n- Transport mechanisms (streamable HTTP, stdio)\n- Tool, resource, and prompt definitions\n\n#### 1.3 Study Framework Documentation\n\n**Recommended stack:**\n- **Language**: TypeScript (high-quality SDK support and good compatibility in many execution environments e.g. MCPB. Plus AI models are good at generating TypeScript code, benefiting from its broad usage, static typing and good linting tools)\n- **Transport**: Streamable HTTP for remote servers, using stateless JSON (simpler to scale and maintain, as opposed to stateful sessions and streaming responses). stdio for local servers.\n\n**Load framework documentation:**\n\n- **MCP Best Practices**: [📋 View Best Practices](./reference/mcp_best_practices.md) - Core guidelines\n\n**For TypeScript (recommended):**\n- **TypeScript SDK**: Use WebFetch to load `https://raw.githubusercontent.com/modelcontextprotocol/typescript-sdk/main/README.md`\n- [⚡ TypeScript Guide](./reference/node_mcp_server.md) - TypeScript patterns and examples\n\n**For Python:**\n- **Python SDK**: Use WebFetch to load `https://raw.githubusercontent.com/modelcontextprotocol/python-sdk/main/README.md`\n- [🐍 Python Guide](./reference/python_mcp_server.md) - Python patterns and examples\n\n#### 1.4 Plan Your Implementation\n\n**Understand the API:**\nReview the service's API documentation to identify key endpoints, authentication requirements, and data models. Use web search and WebFetch as needed.\n\n**Tool Selection:**\nPrioritize comprehensive API coverage. List endpoints to implement, starting with the most common operations.\n\n---\n\n### Phase 2: Implementation\n\n#### 2.1 Set Up Project Structure\n\nSee language-specific guides for project setup:\n- [⚡ TypeScript Guide](./reference/node_mcp_server.md) - Project structure, package.json, tsconfig.json\n- [🐍 Python Guide](./reference/python_mcp_server.md) - Module organization, dependencies\n\n#### 2.2 Implement Core Infrastructure\n\nCreate shared utilities:\n- API client with authentication\n- Error handling helpers\n- Response formatting (JSON/Markdown)\n- Pagination support\n\n#### 2.3 Implement Tools\n\nFor each tool:\n\n**Input Schema:**\n- Use Zod (TypeScript) or Pydantic (Python)\n- Include constraints and clear descriptions\n- Add examples in field descriptions\n\n**Output Schema:**\n- Define `outputSchema` where possible for structured data\n- Use `structuredContent` in tool responses (TypeScript SDK feature)\n- Helps clients understand and process tool outputs\n\n**Tool Description:**\n- Concise summary of functionality\n- Parameter descriptions\n- Return type schema\n\n**Implementation:**\n- Async/await for I/O operations\n- Proper error handling with actionable messages\n- Support pagination where applicable\n- Return both text content and structured data when using modern SDKs\n\n**Annotations:**\n- `readOnlyHint`: true/false\n- `destructiveHint`: true/false\n- `idempotentHint`: true/false\n- `openWorldHint`: true/false\n\n---\n\n### Phase 3: Review and Test\n\n#### 3.1 Code Quality\n\nReview for:\n- No duplicated code (DRY principle)\n- Consistent error handling\n- Full type coverage\n- Clear tool descriptions\n\n#### 3.2 Build and Test\n\n**TypeScript:**\n- Run `npm run build` to verify compilation\n- Test with MCP Inspector: `npx @modelcontextprotocol/inspector`\n\n**Python:**\n- Verify syntax: `python -m py_compile your_server.py`\n- Test with MCP Inspector\n\nSee language-specific guides for detailed testing approaches and quality checklists.\n\n---\n\n### Phase 4: Create Evaluations\n\nAfter implementing your MCP server, create comprehensive evaluations to test its effectiveness.\n\n**Load [✅ Evaluation Guide](./reference/evaluation.md) for complete evaluation guidelines.**\n\n#### 4.1 Understand Evaluation Purpose\n\nUse evaluations to test whether LLMs can effectively use your MCP server to answer realistic, complex questions.\n\n#### 4.2 Create 10 Evaluation Questions\n\nTo create effective evaluations, follow the process outlined in the evaluation guide:\n\n1. **Tool Inspection**: List available tools and understand their capabilities\n2. **Content Exploration**: Use READ-ONLY operations to explore available data\n3. **Question Generation**: Create 10 complex, realistic questions\n4. **Answer Verification**: Solve each question yourself to verify answers\n\n#### 4.3 Evaluation Requirements\n\nEnsure each question is:\n- **Independent**: Not dependent on other questions\n- **Read-only**: Only non-destructive operations required\n- **Complex**: Requiring multiple tool calls and deep exploration\n- **Realistic**: Based on real use cases humans would care about\n- **Verifiable**: Single, clear answer that can be verified by string comparison\n- **Stable**: Answer won't change over time\n\n#### 4.4 Output Format\n\nCreate an XML file with this structure:\n\n```xml\n<evaluation>\n  <qa_pair>\n    <question>Find discussions about AI model launches with animal codenames. One model needed a specific safety designation that uses the format ASL-X. What number X was being determined for the model named after a spotted wild cat?</question>\n    <answer>3</answer>\n  </qa_pair>\n<!-- More qa_pairs... -->\n</evaluation>\n```\n\n---\n\n# Reference Files\n\n## 📚 Documentation Library\n\nLoad these resources as needed during development:\n\n### Core MCP Documentation (Load First)\n- **MCP Protocol**: Start with sitemap at `https://modelcontextprotocol.io/sitemap.xml`, then fetch specific pages with `.md` suffix\n- [📋 MCP Best Practices](./reference/mcp_best_practices.md) - Universal MCP guidelines including:\n  - Server and tool naming conventions\n  - Response format guidelines (JSON vs Markdown)\n  - Pagination best practices\n  - Transport selection (streamable HTTP vs stdio)\n  - Security and error handling standards\n\n### SDK Documentation (Load During Phase 1/2)\n- **Python SDK**: Fetch from `https://raw.githubusercontent.com/modelcontextprotocol/python-sdk/main/README.md`\n- **TypeScript SDK**: Fetch from `https://raw.githubusercontent.com/modelcontextprotocol/typescript-sdk/main/README.md`\n\n### Language-Specific Implementation Guides (Load During Phase 2)\n- [🐍 Python Implementation Guide](./reference/python_mcp_server.md) - Complete Python/FastMCP guide with:\n  - Server initialization patterns\n  - Pydantic model examples\n  - Tool registration with `@mcp.tool`\n  - Complete working examples\n  - Quality checklist\n\n- [⚡ TypeScript Implementation Guide](./reference/node_mcp_server.md) - Complete TypeScript guide with:\n  - Project structure\n  - Zod schema patterns\n  - Tool registration with `server.registerTool`\n  - Complete working examples\n  - Quality checklist\n\n### Evaluation Guide (Load During Phase 4)\n- [✅ Evaluation Guide](./reference/evaluation.md) - Complete evaluation creation guide with:\n  - Question creation guidelines\n  - Answer verification strategies\n  - XML format specifications\n  - Example questions and answers\n  - Running an evaluation with the provided scripts\n","frontmatter":{"name":"mcp-builder","description":"Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).","license":"Complete terms in LICENSE.txt"},"isInternal":false,"tokens":1922,"sizeBytes":9092},{"name":"openai.yaml","path":"core/skills/builtin/review-agent/agents/openai.yaml","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/review-agent/agents/openai.yaml","title":"Agents Skill","category":"anthropic-skill","format":"yaml","content":"interface:\n  display_name: \"Review Agent\"\n  short_description: \"Find actionable bugs in code changes\"\n  default_prompt: \"Use $review-agent to review the requested code changes and return actionable findings.\"\npolicy:\n  allow_implicit_invocation: false\n","isInternal":false,"tokens":53,"sizeBytes":252},{"name":"SKILL.md","path":"core/skills/builtin/review-agent/SKILL.md","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/review-agent/SKILL.md","title":"review-agent","category":"anthropic-skill","format":"markdown","content":"---\nname: review-agent\ndescription: Perform a read-only, defect-first review of a specified code change and return every actionable finding. Use when another agent delegates review of uncommitted changes, a base-branch diff, a commit, or custom review instructions.\n---\n\n# Review Agent\n\nInspect the requested target directly and return every finding that the author would likely fix.\nDo not modify files, create commits, push branches, post review comments, or delegate the review\nto another agent.\n\n## Review the change\n\n1. Read the applicable `AGENTS.md` instructions.\n2. Inspect the complete diff for the requested target and enough surrounding code to understand\n   each changed path.\n3. Identify concrete regressions introduced by the change. Continue through the whole diff after\n   finding the first issue.\n4. Check the relevant tests and call sites to confirm that each finding is real and actionable.\n\nFor a base-branch review, compare the changes that would actually merge rather than diffing\ndirectly against the branch tip. Resolve the comparison ref to the branch's upstream when that\nupstream exists and is ahead of the local branch; otherwise use the local branch. Run\n`git merge-base HEAD <comparison-ref>`, then inspect `git diff <merge-base-sha>`. If the local\nbranch cannot be resolved, try its configured upstream explicitly before reporting that the target\nis unavailable.\n\nFlag an issue only when all of these are true:\n\n- It affects correctness, security, performance, or maintainability in a meaningful way.\n- It is discrete and actionable.\n- It was introduced by the reviewed change.\n- The affected scenario or call path can be demonstrated from the code.\n- The author would probably fix it if they knew about it.\n\nDo not flag speculative concerns, pre-existing problems, intentional behavior changes, or style\nnits that do not obscure the code.\n\n## Write the result\n\nPresent findings first, ordered by severity. Use one entry per issue in this form:\n\n`[P1] Imperative finding title — path/to/file.rs:line`\n\nFollow the title with one short paragraph explaining the affected scenario and why the behavior is\nwrong. Keep the cited range as small as possible and make sure it overlaps the reviewed diff.\n\nUse these priorities:\n\n- `P0`: universal release blocker or critical failure.\n- `P1`: urgent defect that should be fixed next.\n- `P2`: ordinary defect that should be fixed.\n- `P3`: low-impact issue that is still worth fixing.\n\nIf there are no qualifying findings, say `No findings.` Do not invent a finding to fill the result.\nAfter the findings, add a brief overall assessment and mention any material test gaps or residual\nrisks.\n","frontmatter":{"name":"review-agent","description":"Perform a read-only, defect-first review of a specified code change and return every actionable finding. Use when another agent delegates review of uncommitted changes, a base-branch diff, a commit, or custom review instructions."},"isInternal":false,"tokens":553,"sizeBytes":2661},{"name":"openai.yaml","path":"core/skills/builtin/security-best-practices/agents/openai.yaml","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/security-best-practices/agents/openai.yaml","title":"Agents Skill","category":"anthropic-skill","format":"yaml","content":"interface:\n  display_name: \"Security Best Practices\"\n  short_description: \"Security reviews and secure-by-default guidance\"\n  default_prompt: \"Review this codebase for security best practices and suggest secure-by-default improvements.\"\n","isInternal":false,"tokens":44,"sizeBytes":237},{"name":"golang-general-backend-security.md","path":"core/skills/builtin/security-best-practices/references/golang-general-backend-security.md","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/security-best-practices/references/golang-general-backend-security.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Go (Golang) Security Spec (Go 1.25.x, Standard Library, net/http)\n\nThis document is designed as a **security spec** that supports:\n1) **Secure-by-default code generation** for new Go code.\n2) **Security review / vulnerability hunting** in existing Go code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n--------------------------------------------------------------------\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n- MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session cookies, JWTs, database URLs with credentials, signing keys, client secrets).\n- MUST NOT “fix” security by disabling protections (e.g., `InsecureSkipVerify`, `GOSUMDB=off` for public modules, wildcard CORS + credentials, removing auth checks, disabling CSRF defenses on cookie-auth apps).\n- MUST provide **evidence-based findings** during audits: cite file paths, code snippets, build/deploy configs, and concrete values that justify the claim.\n- MUST treat uncertainty honestly: if a control might exist in infrastructure (reverse proxy, WAF, service mesh, platform config), report it as “not visible in app code; verify at runtime/config.”\n- MUST keep fixes minimal, correct, and production-safe; avoid introducing breaking changes without warning (especially around auth/session flows, and proxies).\n\n--------------------------------------------------------------------\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\nWhen asked to write new Go code or modify existing code:\n- MUST follow every **MUST** requirement in this spec.\n- SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n- MUST prefer safe-by-default APIs and proven libraries over custom security code.\n- MUST avoid introducing new risky sinks (shell execution, dynamic template execution, serving user files as HTML, unsafe redirects, weak crypto, unbounded parsing, etc.).\n\n### 1.2 Passive review mode (always on while editing)\nWhile working anywhere in a Go repo (even if the user did not ask for a security scan):\n- MUST “notice” violations of this spec in touched/nearby code.\n- SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n- MUST systematically search the codebase for violations of this spec.\n- MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n1) Build/deploy entrypoints: `main.go`, `cmd/*`, Dockerfiles, Kubernetes manifests, systemd units, CI workflows.\n2) Go toolchain & dependency policy: Go version, modules, `go.mod/go.sum`, proxy/sumdb settings, govulncheck usage.\n3) Secret management and config loading (env, files, secret stores) + logging patterns.\n4) HTTP server configuration (timeouts, body limits, proxy trust, security headers).\n5) AuthN/AuthZ boundaries, session/cookie settings, token validation.\n6) CSRF protections for cookie-authenticated state-changing endpoints.\n7) Template usage and output encoding (XSS), and any “render template from string” behavior (SSTI).\n8) File handling (uploads/downloads/path traversal/temp files), static file serving.\n9) Injection sinks: SQL, OS command execution, SSRF/outbound fetch, open redirects.\n10) Concurrency/resource exhaustion (unbounded goroutines/queues, missing timeouts/contexts).\n11) Use of `unsafe` / `cgo` / `reflect` in security-sensitive paths.\n12) Debug/diagnostic endpoints (pprof/expvar/metrics) exposure.\n13) Cryptography usage (randomness, password hashing).\n\n--------------------------------------------------------------------\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\nExamples include:\n- `*http.Request` fields: `r.URL.Path`, `r.URL.RawQuery`, `r.Form`, `r.PostForm`, headers, cookies, `r.Body`\n- Path parameters from routers (including values extracted from URL paths)\n- JSON/XML/YAML bodies, multipart form parts, uploaded files\n- Any data from external systems (webhooks, third-party APIs, message queues)\n- Any persisted user content (DB rows) that originated from users\n- Configuration values that might be attacker-influenced in some deployments (headers set by upstream proxies, environment variables in multi-tenant systems)\n\n### 2.2 State-changing request\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook send), or initiate privileged actions.\n\n### 2.3 Required audit finding format\nFor each issue found, output:\n\n- Rule ID:\n- Severity: Critical / High / Medium / Low\n- Location: file path + function/handler name + line(s)\n- Evidence: the exact code/config snippet\n- Impact: what could go wrong, who can exploit it\n- Fix: safe change (prefer minimal diff)\n- Mitigation: defense-in-depth if immediate fix is hard\n- False positive notes: what to verify if uncertain (edge configs, proxy behavior, auth assumptions)\n\n--------------------------------------------------------------------\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common Go misconfigurations.\n\n### 3.1 Toolchain, patching, and dependency hygiene (MUST)\n- MUST run a supported Go major version and keep to the latest patch releases.\n- MUST treat Go standard library patch releases as security-relevant (many security fixes land in stdlib components like `net/http`, `crypto/*`, parsing packages).\n- MUST use Go modules with committed `go.mod` and `go.sum`.\n- MUST NOT disable module authenticity mechanisms for public modules (checksum DB) unless you have a controlled, documented replacement.\n- MUST run `govulncheck` (source scan and/or binary scan) in CI and address findings.\n\n### 3.2 HTTP server baseline (MUST for network-facing services)\nIf the program serves HTTP (directly or via a framework built on `net/http`):\n- MUST configure an `http.Server` with explicit timeouts and header limits.\n- MUST set request body size limits (global and per-route as needed).\n- MUST avoid exposing diagnostic endpoints (pprof/expvar) publicly.\n- SHOULD set a consistent set of security headers (or verify they are set at the edge).\n- MUST set cookie security attributes for any cookies you issue.\n- SHOULD implement rate limiting and abuse controls for auth and expensive endpoints.\n\nIllustrative baseline skeleton (adjust to your project):\n- Create a dedicated mux (avoid implicit global defaults unless intentionally managed).\n- Wrap handlers with: panic-safe error handling, request ID, logging, auth, and limits.\n\n--------------------------------------------------------------------\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### GO-DEPLOY-001: Keep the Go toolchain and standard library updated (security releases)\nSeverity: Medium\n\nNOTE: Upgrading dependencies and the core Go version can break projects in unexpected ways. Focus on only security-critical dependencies and if noticed, let the user know rather than upgrading automatically.\n\nRequired:\n- MUST run a supported Go major release and apply patch releases promptly.\n- SHOULD treat patch releases as security-relevant, even if your application code didn’t change.\n\nInsecure patterns:\n- Production builds pinned to old Go versions without a patching process.\n- Docker images like `golang:1.xx` or custom base images that are not updated regularly.\n- CI pipelines that intentionally suppress Go updates.\n\nDetection hints:\n- Inspect CI (`.github/workflows`, `gitlab-ci.yml`, etc.) for `go-version:` or toolchain setup.\n- Inspect Dockerfiles for `FROM golang:` tags.\n- Inspect `go.mod` `go` directive and any toolchain pinning.\n\nFix:\n- Upgrade to the latest patch of a supported Go version.\n- Add an automated check (CI) that fails when Go is below an approved minimum.\n\nNotes:\n- Go publishes regular minor releases that frequently include security fixes across standard library packages.\n\n---\n\n### GO-SUPPLY-001: Go module authenticity MUST NOT be disabled for public dependencies\nSeverity: High\n\nRequired:\n- MUST keep module checksum verification enabled for public modules.\n- SHOULD commit `go.sum` and treat changes as security-sensitive.\n- MUST NOT use insecure module fetching settings for public modules.\n- MAY configure private module behavior using `GOPRIVATE`/`GONOSUMDB` for private repos, but must do so narrowly and intentionally.\n\nInsecure patterns:\n- `GOSUMDB=off` in CI or production build environments for public modules.\n- `GONOSUMDB=*` or overly broad patterns that effectively disable verification.\n- `GOINSECURE=*` or broad `GOINSECURE` patterns for public modules.\n- `GOPROXY=direct` everywhere without a clear policy.\n\nDetection hints:\n- Search build configs for `GOSUMDB`, `GONOSUMDB`, `GOINSECURE`, `GOPROXY`, `GOPRIVATE`.\n- Look for documentation/scripts that recommend disabling checksum DB “to make builds work”.\n\nFix:\n- Restore defaults for public module verification.\n- For private modules:\n  - Set `GOPRIVATE=your.private.domain/*`\n  - Configure an internal proxy or direct fetching, and restrict `GONOSUMDB` to private patterns only.\n\nNotes:\n- Disabling checksum verification removes an important integrity layer against targeted or compromised upstream delivery.\n\n---\n\n### GO-CONFIG-001: Secrets must be externalized and never logged or committed\nSeverity: High (Critical if credentials are committed)\n\nRequired:\n- MUST load secrets from environment variables, secret managers, or secure config files with restricted permissions.\n- MUST NOT hard-code secrets in Go source, test fixtures that may reach production, or build args.\n- MUST NOT log secrets or full credential-bearing connection strings.\n- SHOULD fail closed in production if required secrets are missing.\n\nInsecure patterns:\n- String constants containing tokens/keys/passwords.\n- `.env` files or config files with secrets committed to repo.\n- Logging `os.Environ()`, dumping full configs, or printing DSNs.\n\nDetection hints:\n- Search for suspicious literals (`API_KEY`, `SECRET`, `PASSWORD`, `Authorization:`).\n- Inspect config loaders and logging statements.\n- Inspect CI logs or debug print paths.\n\nFix:\n- Move secrets to a secret store / environment variables.\n- Redact sensitive fields in logs.\n- Add secret scanning to CI and pre-commit.\n\n---\n\n### GO-HTTP-001: HTTP servers MUST set timeouts and MaxHeaderBytes\nSeverity: High (DoS risk)\n\nRequired:\n- MUST set: `ReadHeaderTimeout`, and SHOULD set `ReadTimeout`, `WriteTimeout`, `IdleTimeout` as appropriate for the service.\n- MUST set `MaxHeaderBytes` to a justified limit for your application.\n- MUST NOT rely on default zero-values for timeouts in production for internet-facing servers.\n\nInsecure patterns:\n- `http.ListenAndServe(\":8080\", handler)` with a default `http.Server` (no explicit timeouts).\n- `&http.Server{}` with timeouts left at zero.\n- Missing `MaxHeaderBytes`.\n\nDetection hints:\n- Search for `http.ListenAndServe(`, `ListenAndServeTLS(`, `Server{` and inspect configured fields.\n- Check for reverse proxies; even with a proxy, app-level timeouts still matter.\n\nFix:\n- Use `http.Server{ReadHeaderTimeout: ..., ReadTimeout: ..., WriteTimeout: ..., IdleTimeout: ..., MaxHeaderBytes: ...}`.\n- Calibrate timeouts per endpoint type (streaming vs JSON APIs).\n\nNotes:\n- Net/http documents that these timeouts exist and that zero/negative values mean “no timeout”; production services should choose explicit values.\n\n---\n\n### GO-HTTP-002: Request body and multipart parsing MUST be size-bounded\nSeverity: Medium (DoS risk; can be High for upload-heavy apps)\n\nRequired:\n- MUST enforce a global maximum request body size for endpoints that accept bodies.\n- MUST enforce strict multipart upload limits and avoid unbounded form parsing.\n- SHOULD enforce per-route limits when some endpoints legitimately need larger bodies.\n- SHOULD set upstream (proxy) limits as defense-in-depth.\n\nInsecure patterns:\n- Reading `r.Body` with `io.ReadAll(r.Body)` without a size cap.\n- Calling `r.ParseMultipartForm(...)` with overly large limits (or forgetting size controls).\n- Accepting file uploads with no limits on file size, number of parts, or total body size.\n\nDetection hints:\n- Search for `io.ReadAll(r.Body)`, `json.NewDecoder(r.Body)`, `ParseMultipartForm`, `FormFile`, `multipart`.\n- Look for missing `http.MaxBytesReader` or equivalent per-handler limiting.\n- Look for “upload” endpoints and check limits.\n\nFix:\n- Wrap request bodies with `http.MaxBytesReader(w, r.Body, maxBytes)` before parsing.\n- For multipart, set conservative limits and validate file sizes/part counts explicitly.\n- Set proxy limits (e.g., at ingress) in addition to app limits.\n\nNotes:\n- There are known vulnerability classes and advisories related to excessive resource consumption in multipart/form parsing; treat unbounded parsing as a security issue.\n\n---\n\n### GO-DEPLOY-002: Diagnostic endpoints (pprof/expvar/metrics) MUST NOT be publicly exposed\nSeverity: High\n\nNOTE: This only applies to production configurations. These endpoints are often used for debug or dev endpoints. If found, confirm that it would be reachable from the actual production deployment.\n\nRequired:\n- MUST NOT expose `net/http/pprof` handlers on a public internet-facing listener without strong access controls.\n- SHOULD run diagnostics on a separate, internal-only listener (loopback/VPC-only) and require auth.\n- MUST review what diagnostic endpoints reveal (stack traces, memory, command lines, environment, internal URLs).\n\nInsecure patterns:\n- Side-effect import `import _ \"net/http/pprof\"` in a server binary with a public mux.\n- `/debug/pprof/*` reachable without auth.\n- `/debug/vars` (expvar) reachable without auth.\n\nDetection hints:\n- Search for `net/http/pprof` imports (including blank imports).\n- Search for route prefixes `/debug/pprof`, `/debug/vars`.\n- Check whether `http.DefaultServeMux` is used and whether any debug handlers register globally.\n\nFix:\n- Remove diagnostics from production builds, or bind them to an internal-only listener.\n- Add strong authentication/authorization (and ideally network-level restrictions).\n\nNotes:\n- pprof is typically imported for its side effect of registering HTTP handlers under `/debug/pprof/`.\n\n---\n\n### GO-HTTP-003: Reverse proxy and forwarded header trust MUST be explicit\nSeverity: High (auth, URL generation, logging/auditing correctness)\n\nRequired:\n- If behind a reverse proxy, MUST define which proxy is trusted and how client IP/scheme/host are derived.\n- MUST NOT trust `X-Forwarded-For`, `X-Forwarded-Proto`, `Forwarded`, or similar headers from the open internet.\n- MUST ensure “secure cookie” logic, redirects, and absolute URL generation do not rely on spoofable headers.\n\nInsecure patterns:\n- Using `r.Header.Get(\"X-Forwarded-For\")` as the client IP without validating the proxy boundary.\n- Deriving “is HTTPS” from `X-Forwarded-Proto` without confirming it came from a trusted proxy.\n- Using forwarded `Host` values for password reset links without allowlisting.\n\nDetection hints:\n- Search for `X-Forwarded-For`, `X-Forwarded-Proto`, `Forwarded`, `Real-IP`, and any custom “client IP” helpers.\n- Inspect ingress/proxy configs; if not visible, mark as “verify at edge”.\n\nFix:\n- Enforce proxy trust at the edge and in app:\n  - Accept forwarded headers only from known proxy IP ranges.\n  - Prefer platform-provided mechanisms where available.\n- If generating external links, use a configured allowlisted canonical origin (not the request’s Host header).\n\n---\n\n### GO-HTTP-004: Security headers SHOULD be set (in app or at the edge)\nSeverity: Medium\n\nRequired (typical web app serving browsers):\n- SHOULD set:\n  - `Content-Security-Policy` (CSP) appropriate to the app. NOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n  - `X-Content-Type-Options: nosniff`\n  - Clickjacking protection (`X-Frame-Options` and/or CSP `frame-ancestors`)\n  - `Referrer-Policy` and `Permissions-Policy` where appropriate\n- MUST ensure cookies have secure attributes (see GO-HTTP-005).\n\nNOTE:\n- These headers may be set via reverse proxy/CDN; if not visible in app code, report as “verify at edge”.\n\nInsecure patterns:\n- No security headers anywhere (app or edge) for a browser-facing app.\n- CSP missing for apps rendering untrusted content.\n\nDetection hints:\n- Search for middleware setting headers: `w.Header().Set(\"Content-Security-Policy\", ...)`, etc.\n- Search for reverse proxy config that sets headers.\n\nFix:\n- Add centralized header middleware in Go, or configure at the edge.\n- Keep CSP realistic; avoid `unsafe-inline` where possible.\n\n---\n\n### GO-HTTP-005: Cookies MUST use secure attributes in production\nSeverity: Medium\n\nRequired (production, HTTPS):\n- MUST set `Secure` on cookies that carry auth/session state. IMPORTANT NOTE: Only set `Secure` in production environment when TLS is configured. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n- MUST set `HttpOnly` on auth/session cookies.\n- SHOULD set `SameSite=Lax` by default (or `Strict` if compatible), and only use `None` when necessary (and only with `Secure`).\n- SHOULD set bounded lifetimes (`Max-Age`/`Expires`) appropriate to the app.\n\nInsecure patterns:\n- Setting auth/session cookies without `Secure` in HTTPS deployments.\n- Cookies without `HttpOnly` for session identifiers.\n- `SameSite=None` for cookie-authenticated apps without a strong CSRF strategy.\n\nDetection hints:\n- Search for `http.SetCookie`, `&http.Cookie{`, `Set-Cookie`.\n- Inspect cookie flags in auth/session code.\n\nFix:\n- Set the correct fields on `http.Cookie` and centralize cookie creation.\n\nNotes:\n- SameSite is defense-in-depth and does not replace CSRF protections for cookie-auth apps.\n\n---\n\n### GO-HTTP-006: Cookie-authenticated state-changing endpoints MUST be CSRF-protected\nSeverity: High\n\n- IMPORTANT NOTE: If cookies are not used for auth (e.g., pure bearer token in Authorization header with no ambient cookies), CSRF is not a risk for those endpoints.\n\nRequired:\n- MUST protect all state-changing endpoints (POST/PUT/PATCH/DELETE) that rely on cookies for authentication.\n- SHOULD use a well-tested CSRF library/middleware rather than rolling your own.\n- MAY use additional defenses (Origin/Referer checks, Fetch Metadata, SameSite cookies), but tokens remain the primary defense for cookie-authenticated apps.\nIf tokens are impractical, or for small applications:\n* MUST at a minimum require a custom header to be set and set the session cookie SESSION_COOKIE_SAMESITE=lax, as this is the strongest method besides requiring a form token, and may be much easier to implement.\n\n\nInsecure patterns:\n- Cookie-authenticated JSON endpoints that mutate state with no CSRF checks.\n- Using GET for state-changing actions.\n\nDetection hints:\n- Enumerate all non-GET routes and identify auth mechanism.\n- Look for CSRF middleware usage; if absent, treat as suspicious in browser-facing apps.\n\nFix:\n- Add CSRF middleware and ensure it covers all state-changing routes.\n- If the service is an API intended for non-browser clients, avoid cookie auth; use Authorization headers.\n\n---\n\n### GO-HTTP-007: CORS must be explicit and least-privilege\nSeverity: Medium (High if misconfigured with credentials)\n\nRequired:\n- If CORS is not needed, MUST keep it disabled.\n- If CORS is needed:\n  - MUST allowlist trusted origins (do not reflect arbitrary origins)\n  - MUST be careful with credentialed requests; do not combine broad origins with cookies\n  - SHOULD restrict allowed methods/headers\n\nInsecure patterns:\n- `Access-Control-Allow-Origin: *` paired with cookies (`Access-Control-Allow-Credentials: true`).\n- Reflecting `Origin` without validation.\n\nDetection hints:\n- Search for `Access-Control-Allow-` header setting.\n- Search for CORS middleware configuration.\n\nFix:\n- Implement strict origin allowlists and minimal methods/headers.\n- Ensure cookie-auth endpoints are not exposed cross-origin unless required.\n\n---\n\n### GO-XSS-001: Use html/template and avoid bypassing auto-escaping with untrusted data\nSeverity: High\n\nRequired:\n- MUST use `html/template` for HTML rendering (not `text/template`).\n- MUST NOT convert untrusted data into “trusted” template types (`template.HTML`, `template.JS`, `template.URL`, etc.).\n- SHOULD keep templates static and controlled by developers; treat dynamic templates as high risk.\n- MUST NOT serve user-uploaded HTML/JS as active content unless explicitly intended and safely sandboxed.\n\nInsecure patterns:\n- `text/template` used to generate HTML.\n- Using `template.HTML(userInput)` or similar typed wrappers.\n- Directly writing unescaped user content into HTML responses.\n\nDetection hints:\n- Search for `text/template`, `template.New(...).Parse(...)`, and typed wrappers like `template.HTML(`.\n- Inspect handlers that return HTML with string concatenation.\n\nFix:\n- Use `html/template` and pass untrusted data as data, not markup.\n- If you must allow limited HTML, use a vetted HTML sanitizer and still be careful with attributes/URLs.\n\n---\n\n### GO-SSTI-001: Never parse/execute templates from untrusted input (SSTI)\nSeverity: Critical\n\nRequired:\n- MUST NOT call `template.Parse` / `template.ParseFiles` / `template.New(...).Parse(...)` on template text influenced by untrusted input.\n- MUST treat “user-defined templates” as a special high-risk design:\n  - MUST use heavy sandboxing and strict allowlists\n  - MUST isolate execution (process/container boundary) if truly required\n\nInsecure patterns:\n- `tmpl := template.Must(template.New(\"x\").Parse(r.FormValue(\"tmpl\")))`\n- Reading templates from uploads / DB entries and executing them in the same trust domain as server code.\n\nDetection hints:\n- Search for `.Parse(` and trace the origin of the template string.\n- Look for “custom email templates”, “user theming templates”, etc.\n\nFix:\n- Replace with safe substitution mechanisms (no code execution).\n- If templates must be user-controlled, isolate and sandbox aggressively.\n\n---\n\n### GO-PATH-001: Prevent path traversal and unsafe file serving\nSeverity: High\n\nRequired:\n- MUST NOT pass user-controlled paths to `os.Open`, `os.ReadFile`, `http.ServeFile`, or `http.FileServer` without strict validation and base-dir enforcement.\n- MUST treat `..`, absolute paths, and OS-specific path tricks as hostile input.\n- SHOULD store user uploads outside any static web root; serve through controlled handlers.\n- MUST avoid directory listing for sensitive file trees.\n\nInsecure patterns:\n- `http.ServeFile(w, r, r.URL.Query().Get(\"path\"))`\n- `os.Open(filepath.Join(baseDir, userPath))` without checking that the result stays under `baseDir`\n- `http.FileServer(http.Dir(\".\"))` serving the project root or user-writable directories\n\nDetection hints:\n- Search for `ServeFile(`, `FileServer(`, `http.Dir(`, `os.Open(`, `ReadFile(`, `filepath.Join(`.\n- Trace whether path components come from request/DB.\n\nFix:\n- Use an allowlist of file identifiers (e.g., database IDs) mapped to server-side paths.\n- Enforce base directory containment after cleaning and joining.\n- Serve active formats as downloads (`Content-Disposition: attachment`) unless explicitly intended.\n\n---\n\n### GO-UPLOAD-001: File uploads must be validated, stored safely, and served safely\nSeverity: High\n\nRequired:\n- MUST enforce upload size limits (app + edge).\n- MUST validate file type using allowlists and content checks (not only extensions).\n- MUST store uploads outside executable/static roots when possible.\n- SHOULD generate server-side filenames (random IDs) and avoid trusting original names.\n- MUST serve potentially active formats safely (download attachment) unless explicitly intended.\n\nInsecure patterns:\n- Accepting arbitrary file types and serving them back inline.\n- Using user-supplied filename as storage path.\n- Missing size/type validation.\n\nDetection hints:\n- Search for `multipart`, `FormFile`, `ParseMultipartForm`, `io.Copy` to disk.\n- Check where files are stored and how they are served.\n\nFix:\n- Implement allowlist validation + safe storage + safe serving.\n- Add scanning/quarantine workflows where applicable.\n\n---\n\n### GO-INJECT-001: Prevent SQL injection (parameterized queries / ORM)\nSeverity: High\n\nRequired:\n- MUST use parameterized queries or an ORM that parameterizes under the hood.\n- MUST NOT build SQL by string concatenation / `fmt.Sprintf` / string interpolation with untrusted input.\n\nInsecure patterns:\n- `fmt.Sprintf(\"SELECT ... WHERE id=%s\", r.URL.Query().Get(\"id\"))`\n- `query := \"UPDATE users SET role='\" + role + \"' WHERE id=\" + id`\n\nDetection hints:\n- Grep for `SELECT`, `INSERT`, `UPDATE`, `DELETE` and check how query strings are built.\n- Trace untrusted data into `db.Query`, `db.Exec`, `QueryRow`, etc.\n\nFix:\n- Replace with placeholders (`?`, `$1`, etc.) and pass parameters separately.\n- Validate and type-check IDs before use.\n\n---\n\n### GO-INJECT-002: Prevent OS command injection; avoid shelling out with untrusted input\nSeverity: Critical to High (depends on exposure)\n\nRequired:\n- MUST avoid executing external commands with attacker-controlled strings.\n- If subprocess is necessary:\n  - MUST use `exec.CommandContext` with an argument list (not `sh -c`).\n  - MUST NOT pass untrusted input to a shell (`bash -c`, `sh -c`, PowerShell).\n  - SHOULD use strict allowlists for any variable component (subcommand, flags, filenames).\n- MUST assume CLI tools may interpret attacker-controlled args as flags or special values.\n\nInsecure patterns:\n- `exec.Command(\"sh\", \"-c\", userString)`\n- `exec.Command(\"bash\", \"-c\", fmt.Sprintf(\"tool %s\", user))`\n- Calling the shell to get glob expansion for user-supplied globs.\n\nDetection hints:\n- Search for `os/exec`, `exec.Command(`, `CommandContext(`, `\"sh\"`, `\"bash\"`, `\"-c\"`.\n- Trace untrusted input into command name/args.\n\nFix:\n- Use library APIs instead of subprocesses.\n- Hardcode command and allowlist/validate args.\n- If a shell is unavoidable, escape robustly and treat as high risk (prefer avoiding).\n\nNotes:\n- The Go `os/exec` package intentionally does invoke a shell; introducing `sh -c` reintroduces shell injection hazards.\n\n---\n\n### GO-SSRF-001: Prevent SSRF in outbound HTTP requests\nSeverity: Medium (High in cloud/LAN environments)\n\n- Note: For small stand alone projects this is less important. It is most important when deploying into an LAN or with other services listening on the same server.\n\nRequired:\n- MUST treat outbound requests to user-provided URLs as high risk.\n- SHOULD allowlist hosts/domains for any user-influenced URL fetch.\n- SHOULD block access to localhost/private IP ranges/link-local addresses and cloud metadata endpoints.\n- MUST restrict schemes to `http`/`https` (no `file:`, `gopher:`, etc.).\n- MUST set client timeouts and restrict redirects.\n\nInsecure patterns:\n- `http.Get(r.URL.Query().Get(\"url\"))`\n- “URL preview” / “webhook test” endpoints that fetch arbitrary URLs.\n\nDetection hints:\n- Search for `http.Get`, `client.Do`, and URL values derived from requests/DB.\n- Identify features that fetch remote resources.\n\nFix:\n- Parse URLs strictly; enforce scheme and allowlisted hostnames.\n- Resolve DNS and enforce IP-range restrictions (with care for DNS rebinding).\n- Set timeouts, disable redirects unless needed, and cap response sizes.\n\n---\n\n### GO-HTTPCLIENT-001: Outbound HTTP clients MUST set timeouts and close bodies\nSeverity: High (DoS and resource exhaustion)\n\nRequired:\n- MUST set an overall timeout on `http.Client` usage (or equivalent per-request deadlines via context + transport timeouts).\n- MUST ensure `resp.Body.Close()` is called for all successful requests (typically `defer resp.Body.Close()` immediately after error check).\n- SHOULD limit response body reads (do not `io.ReadAll` unbounded responses).\n- SHOULD restrict redirects for security-sensitive fetches (SSRF, auth flows).\n\nInsecure patterns:\n- Using `http.DefaultClient` / `http.Get` for user-influenced destinations with no timeout policy.\n- Missing `defer resp.Body.Close()` leading to resource leaks.\n- `io.ReadAll(resp.Body)` with no limit.\n\nDetection hints:\n- Search for `http.Get(`, `http.Post(`, `client := &http.Client{}` without `Timeout`, `client.Do(` and missing closes.\n- Search for `io.ReadAll(resp.Body)`.\n\nFix:\n- Use a configured client with timeouts.\n- Always close response bodies.\n- Use bounded readers (`io.LimitReader`) for large/untrusted responses.\n\nNotes:\n- The net/http package exposes `DefaultClient` as a zero-valued `http.Client`, which can easily lead to “no timeout” behavior unless configured.\n\n---\n\n### GO-REDIRECT-001: Prevent open redirects\nSeverity: Medium (can be High with auth flows)\n\nRequired:\n- MUST validate redirect targets derived from untrusted input (`next`, `redirect`, `return_to`).\n- SHOULD prefer only same-site relative paths.\n- SHOULD fall back to a safe default on validation failure.\n\nInsecure patterns:\n- `http.Redirect(w, r, r.URL.Query().Get(\"next\"), http.StatusFound)` with no validation.\n\nDetection hints:\n- Search for `http.Redirect(` and check origin of the location.\n\nFix:\n- Allowlist internal paths or known domains.\n- Reject absolute URLs unless explicitly needed and allowlisted.\n\n---\n\n### GO-CRYPTO-001: Cryptographic randomness MUST come from crypto/rand\nSeverity: High (Critical if used for auth/session tokens or keys)\n\nRequired:\n- MUST use `crypto/rand` for:\n  - session IDs, password reset tokens, API keys, CSRF tokens, nonces\n  - encryption keys, signing keys, salts when required\n- MUST NOT use `math/rand` for any security-sensitive value.\n- SHOULD use built-in helpers that produce appropriately strong tokens when available.\n\nInsecure patterns:\n- `math/rand.Seed(time.Now().UnixNano())` followed by token generation for auth or sessions.\n- Using UUIDv4-like constructs built from `math/rand`.\n\nDetection hints:\n- Search for `math/rand`, `rand.Seed`, `rand.Intn` in code that touches auth/session/token flows.\n- Search for custom token generators.\n\nFix:\n- Switch to `crypto/rand` (`rand.Reader`, `rand.Read`, or secure token helpers).\n- Ensure sufficient entropy and use URL-safe encoding.\n\nNotes:\n- The crypto/rand package provides secure randomness APIs and token generation helpers.\n\n---\n\n### GO-AUTH-001: Password storage MUST use adaptive hashing (bcrypt/argon2id) and safe comparisons\nSeverity: High\n\nRequired:\n- MUST hash passwords using an adaptive password hashing function (bcrypt or argon2id).\n- MUST NOT store plaintext passwords or reversible encryption of passwords.\n- MUST compare secrets in constant time when relevant (tokens, MACs, API keys) to reduce timing leaks.\n- SHOULD ensure password policies do not exceed algorithm constraints (e.g., bcrypt has input length limits; handle long passphrases appropriately).\n\nInsecure patterns:\n- `sha256(password)` stored as password hash.\n- Plaintext password storage.\n- Comparing secrets with `==` in timing-sensitive contexts.\n\nDetection hints:\n- Search for `sha1`, `sha256`, `md5` used on passwords.\n- Search for `bcrypt`/`argon2` usage; if absent, suspect.\n- Search for `==` comparisons on tokens/API keys.\n\nFix:\n- Use `bcrypt.GenerateFromPassword` / `CompareHashAndPassword` or argon2id with recommended parameters.\n- Use constant-time compare helpers when comparing MACs/tokens.\n\nNotes:\n- Go provides bcrypt in `golang.org/x/crypto/bcrypt`, and constant-time comparisons in `crypto/subtle`.\n\n---\n\n### GO-CONC-001: Data races and concurrency hazards MUST be treated as security-relevant\nSeverity: Medium to High (depends on what races affect)\n\nRequired:\n- MUST run tests with the race detector (`go test -race`) in CI for security-sensitive services.\n- MUST fix detected races; do not suppress without deep justification.\n- SHOULD treat shared mutable state in handlers as high risk; enforce synchronization or avoid shared mutability.\n\nInsecure patterns:\n- Global maps/slices mutated from multiple goroutines without a mutex.\n- Caches or auth/session state stored in globals without concurrency protection.\n- Racy access to authorization state (can lead to bypasses or inconsistent enforcement).\n\nDetection hints:\n- Search for `var someMap = map[...]...` used in handlers.\n- Look for missing `sync.Mutex`, `sync.Map`, channels, or other synchronization.\n- Ensure CI includes `-race` and that it runs relevant tests.\n\nFix:\n- Add proper synchronization or redesign to avoid shared mutable state.\n- Add race tests and run them continuously.\n\nNotes:\n- The Go race detector only finds races that occur in executed code paths; improve test coverage and run realistic workloads with `-race` where feasible.\n\n---\n\n### GO-UNSAFE-001: Use of unsafe/cgo MUST be minimized and audited like memory-unsafe code\nSeverity: High (Critical in high-risk code paths)\n\nRequired:\n- SHOULD avoid importing `unsafe` in application code unless absolutely necessary.\n- If `unsafe` is used, MUST treat it as “manual memory safety” requiring careful review and test coverage.\n- If `cgo` is used, MUST treat the C/C++ boundary as memory-unsafe; apply secure coding practices on the C side and isolate where possible.\n\nInsecure patterns:\n- Widespread `unsafe.Pointer` casts in parsing, serialization, auth, or network code.\n- `cgo` used for parsing or security boundaries without sandboxing.\n\nDetection hints:\n- Search for `import \"unsafe\"`, `unsafe.Pointer`, `// #cgo`, `import \"C\"`.\n- Prioritize review where unsafe touches untrusted input.\n\nFix:\n- Replace unsafe/cgo usage with safe standard library alternatives where possible.\n- Isolate unsafe code in small, well-tested modules with fuzz/race tests.\n\nNotes:\n- The unsafe package explicitly provides operations that step around Go’s type safety guarantees.\n\n--------------------------------------------------------------------\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\nToolchain & dependencies:\n- `FROM golang:` (Dockerfiles), `go-version:` (CI), `toolchain go` (go.mod), pinned old versions\n- `GOSUMDB=off`, `GOINSECURE`, `GONOSUMDB`, `GOPROXY=direct`\n- `replace` directives in `go.mod` to forks/paths\n- `govulncheck` missing in CI\n\nHTTP server hardening:\n- `http.ListenAndServe(`, `ListenAndServeTLS(`, `&http.Server{` with missing timeouts\n- `ReadHeaderTimeout: 0`, `ReadTimeout: 0`, `WriteTimeout: 0`, `IdleTimeout: 0`, missing `MaxHeaderBytes`\n\nBody parsing / DoS:\n- `io.ReadAll(r.Body)`, `json.NewDecoder(r.Body)` without size cap\n- `ParseMultipartForm`, `FormFile`, `multipart.NewReader` without explicit limits\n- Missing `http.MaxBytesReader`\n\nDebug exposure:\n- `import _ \"net/http/pprof\"`\n- `/debug/pprof`, `/debug/vars`\n\nTemplates / XSS / SSTI:\n- `text/template` used for HTML output\n- `template.HTML(`, `template.JS(`, `template.URL(` with user-controlled data\n- `.Parse(` on user-controlled strings\n\nFiles:\n- `http.ServeFile(` with user path\n- `http.FileServer(http.Dir(` pointing at repo root or uploads\n- `os.Open(filepath.Join(base, user))` without containment checks\n\nInjection:\n- SQL building with `fmt.Sprintf`, string concatenation near `db.Query/Exec`\n- `exec.Command(\"sh\",\"-c\", ...)`, `exec.Command(\"bash\",\"-c\", ...)`\n\nSSRF / outbound HTTP:\n- `http.Get(userURL)`, `client.Do(req)` where URL comes from request/DB\n- Missing client timeout, missing `resp.Body.Close()`, unbounded `io.ReadAll(resp.Body)`\n\nCrypto:\n- `math/rand` in token/session generation\n- `InsecureSkipVerify: true`\n- Password hashing with `sha256`/`md5` instead of bcrypt/argon2\n\nConcurrency:\n- Shared maps/slices mutated from handlers without locks\n- CI lacking `go test -race`\n\nAlways try to confirm:\n- data origin (untrusted vs trusted)\n- sink type (template/SQL/subprocess/files/http)\n- protective controls present (limits, validation, allowlists, middleware, network controls)\n\n--------------------------------------------------------------------\n\n## 6) Sources (accessed 2026-01-28)\n\nPrimary Go documentation:\n- Go Security Policy — https://go.dev/doc/security/policy\n- Go Release History (security fixes in patch releases) — https://go.dev/doc/devel/release\n- Go 1.25 Release Notes — https://go.dev/doc/go1.25\n- net/http (server timeouts, MaxHeaderBytes, DefaultClient) — https://pkg.go.dev/net/http\n- html/template (auto-escaping and trusted-template assumptions) — https://pkg.go.dev/html/template\n- crypto/tls (MinVersion defaults, InsecureSkipVerify warnings) — https://pkg.go.dev/crypto/tls\n- crypto/rand (secure randomness, token helpers) — https://pkg.go.dev/crypto/rand\n- crypto/subtle (constant-time comparisons) — https://pkg.go.dev/crypto/subtle\n- os/exec (no shell by default; command execution guidance) — https://pkg.go.dev/os/exec\n- unsafe (bypasses type safety) — https://go.dev/src/unsafe/unsafe.go\n- net/http/pprof (debug endpoints) — https://pkg.go.dev/net/http/pprof\n- cmd/go (module authentication via go.sum/checksum DB; env vars like GOINSECURE) — https://pkg.go.dev/cmd/go\n- Module Mirror and Checksum Database Launched (Go blog) — https://go.dev/blog/module-mirror-launch\n- govulncheck documentation — https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck\n- Go Race Detector documentation — https://go.dev/doc/articles/race_detector\n- bcrypt (password hashing) — https://pkg.go.dev/golang.org/x/crypto/bcrypt\n- Go vulnerability entry example (multipart resource consumption) — https://pkg.go.dev/vuln/GO-2023-1569\n\nOWASP Cheat Sheet Series (general web security):\n- Session Management — https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html\n- CSRF Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html\n- SSRF Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html\n- XSS Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html\n- HTTP Security Response Headers — https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html\n","isInternal":false,"tokens":8580,"sizeBytes":38660},{"name":"javascript-express-web-server-security.md","path":"core/skills/builtin/security-best-practices/references/javascript-express-web-server-security.md","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/security-best-practices/references/javascript-express-web-server-security.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Express (Node.js) Web Security Spec (Express 5.x / 4.19.2+, Node.js LTS)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new Express apps and routes.\n2. **Security review / vulnerability hunting** in existing Express code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session secrets, cookies, tokens).\n* MUST NOT “fix” security by disabling protections (e.g., weakening cookie flags, disabling CSRF defenses for cookie-authenticated apps, enabling permissive CORS, trusting proxy headers from the open internet, turning on debugging/stack traces in production, disabling TLS without a replacement).\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, middleware/config values, and runtime assumptions that justify the claim.\n* MUST treat uncertainty honestly: if a protection might exist in infrastructure (reverse proxy, gateway, WAF, CDN), report it as “not visible in app code; verify at runtime/config.”\n* MUST prefer vetted libraries and platform controls over “roll your own” crypto/auth/session/CSRF. Express explicitly expects the application to validate/handle user input correctly; it does not do this automatically. ([Express][1])\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new Express code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default APIs and proven libraries over custom security code.\n* MUST avoid introducing new risky sinks (shell execution, dynamic code evaluation, unsafe redirects, serving user files as HTML, template rendering from untrusted strings, unsafe filesystem paths, SSRF URL fetch endpoints, etc.).\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in an Express repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. Entrypoints (server/app bootstrap), deployment manifests, Dockerfiles, process manager config, CI/CD.\n2. Express settings + middleware stack order (helmet, parsers, auth, sessions, CSRF, CORS).\n3. Proxy trust (`trust proxy`) and IP/protocol/host handling. ([Express][2])\n4. Auth flows, sessions, cookies, password reset links, redirect handling. ([Express][1])\n5. State-changing routes + CSRF protections (cookie-authenticated apps). ([OWASP Cheat Sheet Series][3])\n6. Template rendering and XSS defenses (HTML generation, CSP, `res.locals`). ([OWASP Cheat Sheet Series][4])\n7. File handling (uploads + downloads + static files) and path traversal. ([Express][5])\n8. Injection classes (SQL, NoSQL, command execution, unsafe deserialization). ([OWASP Cheat Sheet Series][6])\n9. Outbound requests (SSRF) and webhook/callback delivery. ([OWASP Cheat Sheet Series][7])\n10. Rate limiting / brute-force defenses / abuse controls. ([Express][1])\n11. Dependency hygiene / lockfiles / npm audit / vulnerable Express versions. ([Express][1])\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nIn Express, common untrusted inputs include:\n\n* `req.params` (route parameters)\n* `req.query` (query string parameters; can be strings/arrays/objects depending on parsing) ([OWASP Cheat Sheet Series][8])\n* `req.body` from `express.json()`, `express.urlencoded()`, `express.text()`, `express.raw()` ([Express][5])\n* `req.headers` / `req.get(...)`\n* `req.cookies` / `req.signedCookies` (if cookie parsing middleware is used)\n* Upload metadata and filenames (e.g., multer `file.originalname`, `file.mimetype`)\n* Any data from external systems (webhooks, third-party APIs, message queues)\n* Any persisted user content (DB rows) that originated from users\n\nSpecial proxy note:\n\n* If `trust proxy` is enabled, values like `req.ip`, `req.hostname`, and `req.protocol` may be derived from `X-Forwarded-*` headers which **can be attacker-controlled** if your proxy chain is not correctly overwriting/removing them. ([Express][2])\n\n### 2.2 State-changing request\n\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook send), or initiate privileged actions.\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + function/route/middleware name + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common Express misconfigurations.\n\nMinimum baseline targets:\n\n* `helmet()` is used and configured (especially CSP where applicable), and fingerprinting is reduced (disable `x-powered-by`). ([Express][1])\n* A custom 404 handler and a custom error handler exist, and production does not leak internal stack traces. ([Express][1])\n* Cookie/session usage is deliberate:\n\n  * Not using default session cookie names\n  * Cookies use secure attributes (`Secure`, `HttpOnly`, `SameSite`) as appropriate\n  * Cookie-backed sessions never store secrets (they are readable by the client)\n  * Server-side sessions never use MemoryStore in production. ([Express][1])\n* Request body parsing has explicit limits (`express.json({ limit })`, `express.urlencoded({ limit, parameterLimit, depth })`). ([Express][5])\n* `trust proxy` is configured explicitly to match your proxy topology; not blindly `true`. ([Express][2])\n* Login/auth endpoints have brute-force protection and rate limiting. ([Express][1])\n* Dependencies are regularly audited/updated (`npm audit` + advisory response). ([Express][1])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### EXPRESS-INPUT-001: Treat all user input as untrusted and validate it\n\nSeverity: High\n\nRequired:\n\n* MUST validate and normalize untrusted inputs before using them in security-sensitive logic or dangerous sinks (DB queries, redirects, filesystem, HTML output, shell commands). Ensure the untrusted inputs are type checked and structure checked before using or passing forward.\n* SHOULD apply allowlists (known-good) rather than blocklists when feasible.\n* MUST reject or safely handle unexpected types/shapes in `req.query`, `req.params`, and `req.body`.\n\nInsecure patterns:\n\n* Passing `req.query`, `req.params`, `req.body` directly into database/query builders, redirects, filesystem paths, or templates.\n* Assuming `req.query.foo` is always a string (it can be an array/object depending on parsing). ([OWASP Cheat Sheet Series][8])\n\nDetection hints:\n\n* Identify “untrusted-to-sink” flows: request → sink (`res.redirect`, SQL execution, `sendFile`, `child_process`, template render, outbound fetch).\n* Search for direct usage of `req.query.*`, `req.body.*`, `req.params.*` in sensitive calls.\n\nFix:\n\n* Add schema validation (e.g., zod/joi/express-validator) at route boundaries.\n* Normalize types (e.g., force IDs to integers; reject arrays when scalar expected).\n\nNotes:\n\n* Express production security guidance explicitly says input validation/handling is the application’s responsibility. ([Express][1])\n\n---\n\n### EXPRESS-REDIRECT-001: Prevent open redirects; validate redirect targets\n\nSeverity: Medium\n\nRequired:\n\n* MUST validate redirect destinations derived from untrusted input (`next`, `return_to`, `url`).\n* SHOULD allowlist only same-site relative paths (preferred) or a strict allowlist of domains.\n* MUST fall back to a safe default when validation fails.\n\nInsecure patterns:\n\n* `res.redirect(req.query.next)` with no validation.\n* `res.redirect(req.body.url)` or `res.location(...)` using untrusted URLs.\n\nDetection hints:\n\n* Search for `res.redirect(` and `res.location(` and trace the source of the target.\n* Look for query params named `next`, `redirect`, `return`, `url`.\n\nFix:\n\n* Only allow relative paths (starting with `/`) and disallow `//`, backslashes, and encoded variants.\n* If cross-domain redirects are required, allowlist exact hosts and enforce `https`.\n\nNotes:\n\n* Express documentation calls out open redirects as dangerous user input and shows validating the host before redirecting. ([Express][1])\n* Keep Express updated: Express has had an open-redirect-related CVE affecting some versions, and upgrades are part of the mitigation posture. ([NVD][9])\n\n---\n\n### EXPRESS-HEADERS-001: Use Helmet (or equivalent) to set essential security headers\n\nSeverity: Medium\n\nRequired:\n\n* SHOULD use `helmet()` to set common security headers.\n* SHOULD configure CSP realistically (avoid `unsafe-inline` where possible) for pages that render user-influenced content.\n* SHOULD set `X-Content-Type-Options: nosniff`, clickjacking defenses (`X-Frame-Options` or CSP `frame-ancestors`), and appropriate referrer policy.\n\nNOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n\nInsecure patterns:\n\n* No security headers set in app code and no evidence they are set at the edge.\n* CSP missing on apps that display user content.\n* Misconfigured framing headers that unintentionally allow clickjacking.\n\nDetection hints:\n\n* Search for `helmet(` usage; check if CSP is configured or disabled.\n* Search for `res.setHeader(` / `res.set(` for security header setting.\n* If not visible in app code, check nginx/CDN config; otherwise flag “verify at edge.”\n\nFix:\n\n* Add `helmet()` early in middleware order and configure:\n\n  * CSP (`contentSecurityPolicy`)\n  * Frame protections (`frameguard` or CSP `frame-ancestors`)\n  * `X-Content-Type-Options` (`noSniff`)\n\nNotes:\n\n* Express production security best practices recommend Helmet and list headers Helmet sets by default. ([Express][1])\n* OWASP HTTP Headers guidance is a useful reference when tuning policies. ([OWASP Cheat Sheet Series][10])\n\n---\n\n### EXPRESS-FINGERPRINT-001: Reduce fingerprinting by disabling `x-powered-by` and customizing error/404 responses\n\nSeverity: Low (defense-in-depth)\n\nRequired:\n\n* SHOULD disable `X-Powered-By` using `app.disable('x-powered-by')`.\n* SHOULD provide a custom 404 handler and a custom error handler to avoid distinct default responses and to control information leakage.\n\nInsecure patterns:\n\n* Default `X-Powered-By: Express` header left enabled.\n* Default Express 404/error responses in production with identifiable formatting and/or stack traces.\n\nDetection hints:\n\n* Search for `app.disable('x-powered-by')`.\n* Check middleware tail for a custom 404 (`app.use((req,res)=>...)`) and a custom error handler (`app.use((err,req,res,next)=>...)`).\n* Check if `NODE_ENV` is correctly set for production behavior (see EXPRESS-ERROR-001). ([Express][11])\n\nFix:\n\n* Add:\n\n  * `app.disable('x-powered-by')`\n  * A custom 404 handler\n  * A custom error handler that logs server-side and returns generic messages client-side\n\nNotes:\n\n* Express docs explicitly recommend disabling `x-powered-by` and adding your own not-found and error handlers. ([Express][1])\n\n---\n\n### EXPRESS-COOKIE-001: Cookies must use secure attributes and minimal scope\n\nSeverity: Medium\n\nRequired:\n\n* MUST set cookie flags appropriately for any authentication/session cookie:\n\n  * `Secure` when HTTPS (production) IMPORTANT NOTE: Only set `Secure` in production environment if TLS is configured. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n  * `HttpOnly` for auth/session cookies\n  * `SameSite` set deliberately (`Lax` is a common baseline; `Strict` if compatible; `None` only with `Secure` and a justified cross-site need)\n* SHOULD avoid setting `domain` broadly (avoid “all subdomains” unless required).\n* SHOULD set bounded expiry appropriate to risk and UX.\n\nInsecure patterns:\n\n* Session/auth cookies without `HttpOnly`.\n* Cookies without `Secure` in production HTTPS.\n* `SameSite=None` + cookie-authenticated state-changing endpoints without CSRF protections.\n\nDetection hints:\n\n* Search for `res.cookie(`, `Set-Cookie`, `cookie: { ... }`, `express-session`, `cookie-session`.\n* Verify cookie flags in session middleware configuration.\n\nFix:\n\n* Set these attributes centrally in session/cookie middleware configuration.\n\nNotes:\n\n* Express production security guidance lists cookie security options (`secure`, `httpOnly`, etc.). ([Express][1])\n* `res.cookie()` ultimately sets `Set-Cookie` with options; defaults follow RFC 6265 behavior when options are omitted. ([Express][5])\n* OWASP session management guidance is relevant for choosing flags and lifetimes. ([OWASP Cheat Sheet Series][12])\n\n---\n\n### EXPRESS-SESS-001: Do not use the default session cookie name; avoid session fingerprinting\n\nSeverity: Low (defense-in-depth)\n\nRequired:\n\n* SHOULD override the default session cookie name (e.g., do not keep `connect.sid` when using `express-session`).\n* SHOULD use a generic name (e.g., `sessionId`) unless you have a compatibility reason.\n\nInsecure patterns:\n\n* `express-session` used with no `name:` configured (default cookie name).\n* Multiple apps on the same domain sharing a cookie name accidentally.\n\nDetection hints:\n\n* Search for `express-session` config blocks; check for `name:`.\n\nFix:\n\n* Set `name: 'sessionId'` (or similar) in `express-session` options.\n\nNotes:\n\n* Express docs explicitly recommend not using the default session cookie name to reduce fingerprinting. ([Express][1])\n\n---\n\n### EXPRESS-SESS-002: Session storage and lifecycle must be production-safe\n\nSeverity: High\n\nRequired:\n\n* MUST NOT use `MemoryStore` in production (it is not designed for production use).\n* MUST store session secrets outside source control and rotate them safely.\n* SHOULD regenerate sessions on login / privilege changes to reduce session fixation risk.\n* MUST NOT store sensitive secrets in client-readable cookie sessions.\n\nInsecure patterns:\n\n* `app.use(session({ store: new MemoryStore(), ... }))` or missing store (defaults to MemoryStore).\n* Hard-coded for example: `secret: 'keyboard cat'` / `secret: 's3Cur3'` in repo.\n* Using `cookie-session` to store access tokens, refresh tokens, or PII.\n\nDetection hints:\n\n* Search for `express-session` and look for `MemoryStore` usage or missing `store`.\n* Search for `secret:` in session config and check if it’s hard-coded.\n* Look for `req.session = ...` patterns and whether sensitive data is stored.\n\nFix:\n\n* Use a production session store (Redis, database-backed, etc.).\n* Load secrets from environment/secret manager.\n* On login: `req.session.regenerate(...)` or equivalent flow with safe privilege re-binding.\n\nNotes:\n\n* `express-session` explicitly warns that `MemoryStore` is not designed for production. ([Express][1])\n* `express-session` documents rotating secrets and session regeneration to guard against fixation. ([Express][1])\n* Express notes that cookie-backed sessions serialize data into the cookie and that cookie data is visible to the client; keep it small and non-secret. ([Express][1])\n\n---\n\n### EXPRESS-CSRF-001: Cookie-authenticated state-changing requests MUST be CSRF-protected\n\nSeverity: High\n\n- IMPORTANT NOTE: If cookies are not being used for auth (ie auth is via Authentication header or other passed token), then there is no CSRF risk.\n\nRequired:\n\n* MUST protect all state-changing endpoints (POST/PUT/PATCH/DELETE) that rely on cookies for authentication.\n* SHOULD use a well-understood CSRF mitigation (token-based is the typical baseline).\n* MAY add defense-in-depth: Origin/Referer validation, Fetch Metadata enforcement, SameSite cookies, custom header requirements for XHR/fetch—**but do not treat these as a full replacement** unless explicitly designed and justified.\n* MUST use at a minimum require a custom HTTP header if form based CRSF tokens are not practical, as this is the second strongest method.\n\nIMPORTANT NOTE:\n\n* If authentication is done via `Authorization: Bearer ...` headers (and not cookies), classic browser CSRF is typically not applicable;\n\nInsecure patterns:\n\n* Cookie-authenticated endpoints that change state with no CSRF protection.\n* Using GET for state-changing actions (amplifies CSRF risk).\n* “CSRF protection” that only checks a user-controlled field.\n\nDetection hints:\n\n* Enumerate routes with methods other than GET/HEAD and identify whether cookies gate auth.\n* Look for presence/absence of CSRF middleware and token checks.\n* Check JSON APIs too, not only HTML forms.\n\nFix:\n\n* Implement CSRF tokens for cookie-authenticated flows.\n* Add Origin/Referer checks where feasible, and ensure SameSite is set appropriately.\n\nNotes:\n\n* OWASP CSRF guidance and OWASP Node.js guidance both recommend anti-CSRF tokens as a standard control for web apps. ([OWASP Cheat Sheet Series][3])\n\n---\n\n### EXPRESS-CORS-001: CORS must be explicit and least-privilege\n\nSeverity: Medium (High if misconfigured with credentials)\n\nRequired:\n\n* If CORS is not needed, MUST keep it disabled.\n* If CORS is needed:\n\n  * MUST allowlist trusted origins (do not reflect arbitrary `Origin` without validation).\n  * MUST NOT combine broad origins with credentialed cookies (`Access-Control-Allow-Credentials: true`).\n  * SHOULD restrict methods, headers, and exposed headers to what’s required.\n\nInsecure patterns:\n\n* `Access-Control-Allow-Origin: *` with `Access-Control-Allow-Credentials: true`.\n* Reflecting `Origin` for all requests without allowlist validation.\n* Applying permissive CORS middleware globally when only a subset needs cross-origin access.\n\nDetection hints:\n\n* Search for `cors(`, `Access-Control-Allow-Origin`, `Access-Control-Allow-Credentials`.\n* Inspect whether cookies are used for auth on endpoints exposed cross-origin.\n\nFix:\n\n* Implement strict origin allowlist and ensure credentialed requests only for intended origins.\n* Consider splitting CORS config per route group rather than global.\n\nNotes:\n\n* OWASP HTTP header guidance covers security implications of response headers, including those that affect browser behavior; use it as a reference when reviewing header posture. ([OWASP Cheat Sheet Series][10])\n\n---\n\n### EXPRESS-PROXY-001: Reverse proxy trust (`trust proxy`) must be configured correctly\n\nSeverity: Medium (High if using IP based authentication)\n\nRequired:\n\n* If behind a reverse proxy/LB, MUST configure `app.set('trust proxy', ...)` to match the real proxy chain.\n* MUST NOT blindly set `trust proxy = true` unless you fully control the proxy behavior and header rewriting.\n* MUST ensure the last trusted proxy overwrites/removes `X-Forwarded-For`, `X-Forwarded-Host`, and `X-Forwarded-Proto` so clients cannot spoof them.\n\nInsecure patterns:\n\n* `app.set('trust proxy', true)` in an app directly exposed to the internet or behind unknown proxies.\n* Using `req.ip`, `req.protocol`, `req.hostname` for security decisions without correct proxy trust configuration.\n* Rate limiting keyed by `req.ip` with spoofable forwarded headers.\n\nDetection hints:\n\n* Search for `app.set('trust proxy'`.\n* Check infra docs (nginx/LB) for header rewriting behavior.\n* Identify any security logic using `req.ip`, `req.ips`, `req.protocol`, `req.hostname`.\n\nFix:\n\n* Set `trust proxy` to a hop count, explicit IP/subnet list, or a custom function matching your network.\n* Ensure proxies overwrite forwarded headers.\n\nNotes:\n\n* Express explicitly warns that when `trust proxy` is `true`, the client IP is derived from `X-Forwarded-For`, and if proxies don’t overwrite forwarded headers, the client can provide any value. It also describes that enabling trust proxy impacts `req.hostname` and `req.protocol` derived from forwarded headers. ([Express][2])\n\n---\n\n### EXPRESS-BODY-001: Request body size and parsing limits MUST be set appropriately\n\nSeverity: Low\n\nRequired:\n\n* SHOULD set explicit body size limits for:\n\n  * `express.json({ limit })`\n  * `express.urlencoded({ limit, parameterLimit, depth })`\n* SHOULD only enable the parsers you need; do not parse large bodies by default for all routes.\n* SHOULD enforce additional limits at the reverse proxy / gateway level.\n\nInsecure patterns:\n\n* No explicit body limits (accepting arbitrarily large JSON/urlencoded).\n* Global parsers applied to all routes when only some need bodies.\n* `parameterLimit` very high without justification (DoS potential).\n\nDetection hints:\n\n* Search for `express.json(` and confirm `limit` is set (or consciously accepted).\n* Search for `express.urlencoded(` and inspect `limit`, `parameterLimit`, and `depth`.\n* Review upload/webhook endpoints for special parsing needs.\n\nFix:\n\n* Configure parsers with conservative defaults and override per route group when needed.\n\nNotes:\n\n* Express documents `express.json` options (including `limit`, defaulting to 100kb) and explicitly notes `req.body` is untrusted and should be validated. ([Express][5])\n* Express documents `express.urlencoded` options including `limit`, `parameterLimit`, and `depth`. ([Express][5])\n* OWASP Node.js guidance also recommends setting request size limits. ([OWASP Cheat Sheet Series][8])\n\n---\n\n### EXPRESS-INPUT-002: Prevent HTTP Parameter Pollution and type confusion in `req.query`\n\nSeverity: Medium\n\nRequired:\n\n* MUST treat `req.query` values as potentially multi-valued (array/object), depending on query parsing.\n* SHOULD reject ambiguous multi-valued parameters for security-sensitive fields (e.g., `role`, `isAdmin`, `redirect`, `amount`, `userId`).\n* SHOULD consider explicit parsing or dedicated middleware if parameter pollution is a concern.\n\nInsecure patterns:\n\n* `if (req.query.admin) { ... }` without type checks (arrays/objects may coerce truthy).\n* Passing `req.query` directly into ORM/NoSQL query objects.\n\nDetection hints:\n\n* Search for security-sensitive comparisons on `req.query.*` without type enforcement.\n* Look for code that assumes query params are strings.\n\nFix:\n\n* Validate shape: enforce string-only for certain params and reject arrays/objects.\n* Normalize query parsing settings (simple vs extended) where applicable and documented.\n\nNotes:\n\n* OWASP Node.js cheat sheet explicitly highlights that Express query parsing can produce strings, arrays, or objects and recommends preventing HTTP Parameter Pollution. ([OWASP Cheat Sheet Series][8])\n\n---\n\n### EXPRESS-XSS-001: Prevent reflected/stored XSS in HTML responses and templating\n\nSeverity: High\n\nRequired:\n\n* MUST escape untrusted content in HTML output (templates should auto-escape by default; do not bypass).\n* MUST NOT inject untrusted strings into HTML without escaping/sanitization.\n* SHOULD set CSP (via Helmet) for apps rendering user-controlled content.\n* SHOULD keep `res.locals` free of user-controlled input intended for templates unless it is validated/escaped.\n\nInsecure patterns:\n\n* `res.send(\"<div>\" + req.query.q + \"</div>\")`\n* Passing untrusted HTML through “safe” template flags/filters.\n* Writing untrusted strings into `res.locals` and then rendering without escaping.\n\nDetection hints:\n\n* Search for `res.send(` with strings containing user input.\n* Search for template “safe” flags (engine-specific) and trace data origin.\n* Search for assignments to `res.locals` and whether they might contain untrusted data.\n\nFix:\n\n* Use a template engine with autoescaping; pass only validated data.\n* For rich text that must contain HTML, use a trusted sanitizer and an allowlist policy.\n* Add CSP with realistic directives.\n\nNotes:\n\n* Express API docs explicitly warn that `res.locals` “should not contain user-controlled input” and is often used to expose things like CSRF tokens to templates. ([Express][5])\n* OWASP XSS prevention guidance provides standard output-encoding and policy recommendations. ([OWASP Cheat Sheet Series][4])\n* Helmet can mitigate some XSS classes via headers such as CSP. ([Express][1])\n\n---\n\n### EXPRESS-TEMPLATE-001: Never render untrusted templates or template paths (SSTI / LFI risk)\n\nSeverity: Critical (if you can prove template strings/paths are user/attacker-controlled)\n\nRequired:\n\n* MUST NOT render templates whose contents or template path/name is influenced by untrusted input.\n* MUST NOT load templates from user-controlled filesystem locations.\n* SHOULD treat “email template editors”, “theme engines”, and “CMS-like template storage” as high-risk designs requiring sandboxing and isolation.\n\nInsecure patterns:\n\n* `res.render(req.query.view, data)` where `view` is not allowlisted.\n* Rendering a template from a string that includes user input (engine-specific).\n* Loading templates from uploads directories.\n\nDetection hints:\n\n* Search for `res.render(` where the first argument is derived from request/DB without allowlist.\n* Search for template compilation APIs (engine-specific) fed by user content.\n\nFix:\n\n* Use allowlisted template names and a fixed templates directory.\n* If user-defined templates are required, implement strict sandboxing and isolate execution.\n\nNotes:\n\n* Express’s template system depends on the chosen engine; assume unsafe if user input influences template selection or source.\n\n---\n\n### EXPRESS-FILES-001: Prevent path traversal and unsafe file serving (sendFile/download)\n\nSeverity: High\n\nRequired:\n\n* MUST NOT pass user-controlled filesystem paths directly to `res.sendFile()` / `res.download()` / filesystem APIs.\n* SHOULD use `res.sendFile` with a fixed `root` and strict options (e.g., deny dotfiles) when serving user-selected files from a directory.\n* MUST enforce authorization checks before serving user-specific files.\n\nInsecure patterns:\n\n* `res.sendFile(req.query.path)` or `res.download(req.params.file)` with no root restriction.\n* File-serving routes that accept `..` segments, encoded traversal, or absolute paths.\n\nDetection hints:\n\n* Search for `res.sendFile(` and trace the `path` argument origin.\n* Search for `res.download(` and trace the `path` argument origin.\n* Look for `fs.readFile`/`createReadStream` on paths derived from requests.\n\nFix:\n\n* Use an identifier-to-path mapping stored server-side (DB), not raw paths from clients.\n* Use `root: <trusted_base_dir>` and `dotfiles: 'deny'` where appropriate; validate the filename component strictly.\n\nNotes:\n\n* Express’s `res.sendFile` docs show using a `root` option and `dotfiles: 'deny'` as part of a safe serving configuration. ([Express][5])\n* `res.download` transfers the file as an attachment, but you still must control/validate the underlying `path`. ([Express][5])\n\n---\n\n### EXPRESS-STATIC-001: Harden `express.static` / serve-static and never serve untrusted uploads as active content\n\nSeverity: Medium (if serving untrusted user files if there are not robust limits tot eh file extensions)\n\nRequired:\n\n* MUST NOT serve user uploads from a public static directory as active content (especially HTML/JS/SVG) unless explicitly intended and sandboxed. If sure that the content is inactive (png, jpg, other images etc) then it may be safe. It may be good to validate image file extensions are allow-listed before serving them.\n* SHOULD configure static serving to:\n\n  * deny/ignore dotfiles\n  * avoid unintended directory indexes if not needed\n  * apply appropriate cache controls for immutable assets\n\nInsecure patterns:\n\n* `app.use(express.static('uploads'))` where users can upload arbitrary files.\n* Serving uploaded HTML or SVG inline from the same origin as the app.\n\nDetection hints:\n\n* Search for `express.static(` and identify served directories.\n* Compare served directories with upload storage locations.\n* Check for `dotfiles` and `index` options in static middleware.\n\nFix:\n\n* Store uploads outside any static web root and serve via controlled routes that set safe `Content-Type` and `Content-Disposition: attachment` when appropriate.\n* Configure `express.static(root, { dotfiles: 'deny'|'ignore', index: false (if desired) })`.\n\nNotes:\n\n* Express documents `express.static` options, including `dotfiles` behavior and `index`. ([Express][5])\n\n---\n\n### EXPRESS-UPLOAD-001: File uploads must be validated, stored safely, and served safely\n\nSeverity: Low - Medium\n\nRequired:\n\n* SHOULD enforce upload size limits (app + edge).\n* MUST validate file type using allowlists and content checks (not only filename extension).\n* MUST store uploads outside executable/static roots when possible.\n* SHOULD generate server-side filenames (random IDs); do not trust original names.\n* MUST serve potentially active formats safely (download attachment) unless explicitly intended.\n\nInsecure patterns:\n\n* Accepting arbitrary file types and serving them back inline.\n* Using `file.originalname` as the storage path.\n* Missing size/type validation.\n\nDetection hints:\n\n* Look for multer/busboy/formidable usage and check for `limits`.\n* Check where uploaded files are written and how they are served.\n* Check whether uploads end up under `public/` or any `express.static` root.\n\nFix:\n\n* Implement allowlist validation + safe storage + safe serving, per OWASP upload guidance.\n\nNotes:\n\n* OWASP File Upload guidance covers allowlists, content validation, storage, and safe serving patterns. ([OWASP Cheat Sheet Series][13])\n\n---\n\n### EXPRESS-INJECT-001: Prevent SQL injection (use parameterized queries / ORM)\n\nSeverity: High\n\nRequired:\n\n* MUST use parameterized queries or an ORM/query builder that parameterizes under the hood.\n* MUST NOT build SQL via string concatenation/template literals with untrusted input.\n\nInsecure patterns:\n\n* ``db.query(`SELECT * FROM users WHERE id = ${req.query.id}`)``\n* `\"SELECT ... WHERE name = '\" + req.body.name + \"'\"`\n\nDetection hints:\n\n* Grep for `SELECT`, `INSERT`, `UPDATE`, `DELETE` strings in JS/TS.\n* Trace untrusted input into `.query(...)`, `.execute(...)`, or raw SQL APIs.\n\nFix:\n\n* Replace with parameterized queries (placeholders) or ORM query APIs.\n* Validate types (e.g., integer IDs) before querying.\n\nNotes:\n\n* OWASP SQL injection prevention guidance strongly favors parameterized queries. ([OWASP Cheat Sheet Series][6])\n\n---\n\n### EXPRESS-INJECT-002: Prevent NoSQL injection / operator injection (Mongo-style)\n\nSeverity: High (app-dependent)\n\nRequired:\n\n* MUST validate types and schemas for any query object built from untrusted input.\n* MUST prevent operator injection (e.g., `$ne`, `$gt`, `$where`) if user input is merged into query objects.\n* SHOULD consider defensive libraries/middleware when appropriate.\n\nInsecure patterns:\n\n* `collection.find(req.body)` where the body is attacker-controlled.\n* Merging `req.query`/`req.body` into Mongo queries without schema validation.\n\nDetection hints:\n\n* Search for `find(`, `findOne(`, `aggregate(` calls where argument is request-derived.\n* Check for patterns like `{ ...req.query }` or `Object.assign(query, req.body)`.\n\nFix:\n\n* Use schema validation at boundary; explicitly construct query objects from validated fields only.\n\nNotes:\n\n* OWASP Node.js cheat sheet discusses input validation and mentions Node ecosystem modules commonly used for sanitization in NoSQL contexts. ([OWASP Cheat Sheet Series][8])\n\n---\n\n### EXPRESS-CMD-001: Prevent OS command injection (child_process)\n\nSeverity: Critical to High (depends on exposure), please prove it is user/attacker controlled\n\nRequired:\n\n* MUST avoid executing shell commands with untrusted input.\n* If subprocess is necessary:\n\n  * MUST avoid `exec()` / `execSync()` with attacker-influenced strings\n  * MUST NOT use `shell: true` with attacker-influenced data\n  * SHOULD use `spawn()` with an argument array and strict allowlists. Ensure the executable is hardcoded or allow-listed, do not use a user supplied command name.\n  * SHOULD place user-controlled values after `--` when supported by the subcommand to avoid flag injection\n\nInsecure patterns:\n\n* `exec(req.query.cmd)`\n* `exec(`convert ${userPath} ...`)`\n* `spawn('sh', ['-c', userString])`\n* `spawn(userString, ['foo'])`\n\nDetection hints:\n\n* Search for `child_process`, `exec(`, `execSync(`, `spawn(`, `fork(`.\n* Trace request/DB data into command construction.\n\nFix:\n\n* If possible, write the functionality in javascript or use a library instead of subprocess.\n* If unavoidable, hard-code command and strictly allowlist parameters.\n\nNotes:\n\n* OWASP OS command injection defense guidance covers avoid-shell and allowlist patterns. ([OWASP Cheat Sheet Series][14])\n\n---\n\n### EXPRESS-SSRF-001: Prevent server-side request forgery (SSRF) in outbound HTTP\n\nSeverity: Medium (High in cloud/LAN deployments)\n\nNOTE: This is mostly only applicable to apps which will be deployed in a cloud/LAN setup or have other http services on the same box. Sometimes the feature requires this functionality unavoidably (webhooks).\n\nRequired:\n\n* MUST treat outbound requests to user-provided URLs as high risk if there are other reachable private http endpoints.\n* SHOULD validate and restrict destinations (allowlist hosts/domains) for any user-influenced URL fetch.\n* SHOULD block access to:\n\n  * localhost / private IP ranges / link-local\n  * cloud metadata endpoints\n* MUST allow only `http`/`https` for URL fetch features (to avoid schemas such as `file:`,`javascript:`)\n* SHOULD set timeouts and restrict redirects.\n\nInsecure patterns:\n\n* `fetch(req.query.url)`\n* “URL preview” / “import from URL” endpoints that accept arbitrary URLs.\n\nDetection hints:\n\n* Search for `fetch(`, `axios(`, `got(`, `request(`, `node-fetch` usage where URL originates from users/DB.\n* Review webhook testers, previewers, image fetchers.\n\nFix:\n\n* Enforce scheme allowlist, host allowlist, DNS/IP resolution checks, timeouts, and redirect policy.\n* Consider network egress controls at infrastructure level.\n\nNotes:\n\n* OWASP SSRF prevention guidance provides standard controls and common pitfalls. ([OWASP Cheat Sheet Series][7])\n\n---\n\n### EXPRESS-ERROR-001: Error handling MUST not leak sensitive details in production\n\nSeverity: Low\n\nRequired:\n\n* SHOULD define a centralized error handler (`app.use((err, req, res, next) => ...)`) at the end of middleware.\n* MUST avoid returning stack traces, internal error messages, or secrets to clients in production.\n* SHOULD log errors server-side with appropriate redaction.\n* SHOULD ensure the app runs with production settings so default behavior doesn’t leak details.\n* MUST avoid logging or returning sensitive information such as secrets, env vars, sessions, cookies in error messages in production.\n\nInsecure patterns:\n\n* Returning `err.stack` to clients.\n* Using dev-only error middleware in production.\n* `NODE_ENV` left as development, causing verbose error responses.\n\nDetection hints:\n\n* Verify there is a final error-handling middleware.\n* Search for `res.status(500).send(err)` or similar.\n* Check production environment variables and startup scripts.\n\nFix:\n\n* Add a production-safe error handler that returns generic messages and logs details internally.\n* Ensure environment is configured for production behavior.\n\nNotes:\n\n* Express production security guidance recommends custom error handling. ([Express][1])\n* Express error handling docs describe the default error handler behavior and how production mode affects what is exposed. ([Express][11])\n\n---\n\n### EXPRESS-AUTH-001: Prevent brute-force attacks against authorization endpoints\n\nSeverity: Medium\n\nNOTE: This is highly application specific and while it is good to bring to the attention of the user, it is hard to fix without additional complex configurations. Prefer to inform the user and if they request you to help implement a solution, help walk them through possible solutions.\n\nRequired:\n\n* SHOULD protect login/auth endpoints against brute forcing.\n* SHOULD rate-limit by:\n\n  1. consecutive failed attempts per username+IP\n  2. failed attempts per IP over a time window\n\nInsecure patterns:\n\n* Unlimited login attempts.\n\nDetection hints:\n\n* Identify all auth endpoints and check for rate limiting/throttling.\n* Search for `rate-limiter-flexible`, `express-rate-limit`, or gateway policies.\n\nFix:\n\n* Implement rate-limiting/throttling (app or edge). Express docs point to `rate-limiter-flexible` as a tool for this approach. ([Express][1])\n\nNotes:\n\n* OWASP Node.js cheat sheet also recommends precautions against brute forcing. ([OWASP Cheat Sheet Series][8])\n\n---\n\n### EXPRESS-DEPS-001: Dependency and patch hygiene (Express + Node + critical middleware)\n\nSeverity: Medium / Low\n\nNOTE: `npm audit` often returns a large number of insignificant \"vulnerabilities\" which do not actually matter. You should only focus on Express or other extremely critical packages, ignoring ones listed in dev tools, bundlers, etc.\n\nDo not upgrade packages without concent from the user. This may break existing code in unexpected ways. Instead, inform them of the outdated packages.\n\nRequired:\n\n* MUST keep Express on a maintained version line (avoid EOL major versions).\n* MAY use `npm audit` in CI and during maintenance work.\n* SHOULD pin dependencies via lockfiles and review major updates carefully.\n\nInsecure patterns:\n\n* Running EOL Express versions (e.g., very old major lines).\n* Ignoring `npm audit` findings without triage.\n* Unpinned dependency ranges that auto-upgrade into insecure versions.\n\nDetection hints:\n\n* Check `package.json` and lockfiles for `express` version and other critical middleware versions.\n* Inspect CI pipelines for `npm audit`/SCA steps.\n\nFix:\n\n* Upgrade to latest stable Express and apply patches.\n* Add automated dependency scanning and upgrade process.\n\nNotes:\n\n* Express production security guidance emphasizes that dependency vulnerabilities can compromise the app, and recommends `npm audit`. ([Express][1])\n* Track security issues affecting Express versions (including known open-redirect-related CVEs). ([NVD][9])\n\n---\n\n### EXPRESS-DOS-001: Configure DoS protections (timeouts, limits, reverse proxy)\n\nSeverity: Low\n\nNOTE: It may be hard to tell from the provided application context if the application runs behind a reverse proxy. You can inform the user or recommend one, but do not attempt to configure one without them initiating it. This is highly deployment dependant.\n\nRequired:\n\n* SHOULD use a reverse proxy to provide caching, load balancing, and filtering controls when feasible.\n* MAY configure server/proxy timeouts and connection limits to reduce exposure to Slowloris and similar DoS patterns.\n* MUST ensure server/socket errors are handled so malformed connections do not crash the process. (Express should handle exceptions, but there are edgecases)\n\nInsecure patterns:\n\n* No reverse proxy in front of a public Node server, with defaults everywhere.\n* Missing error handlers on server/socket objects.\n* Extremely permissive timeouts and unlimited body sizes.\n\nDetection hints:\n\n* Inspect server creation (`http.createServer`, `https.createServer`) and whether timeouts are set.\n* Check proxy/gateway config for timeouts and max body size.\n\nFix:\n\n* Explain how to configure reverse proxy and timeouts, set request size limits\n* add robust error handling middleware\n\nNotes:\n\n* Node’s security guidance for HTTP DoS discusses using reverse proxies and correctly configuring server timeouts. ([Node.js][15])\n\n---\n\n### EXPRESS-NODE-INSPECT-001: Do not expose the Node inspector in production\n\nSeverity: Critical\n\nNOTE: Ensure that this detection is actually in the production path, and not just being used for local debugging.\n\nRequired:\n\n* MUST NOT run Node with `--inspect` (especially bound to non-loopback) in production.\n* MUST ensure `NODE_OPTIONS` or startup scripts do not enable inspector in prod.\n* SHOULD firewall/debug locally only.\n\nInsecure patterns:\n\n* `node --inspect=0.0.0.0:9229 app.js` in production.\n* Container/PM2/systemd configs enabling inspector.\n\nDetection hints:\n\n* Search for `--inspect` in Dockerfiles, Procfiles, systemd units, PM2 configs, npm scripts.\n* Check `NODE_OPTIONS`.\n\nFix:\n\n* Remove inspector flags from production start commands; restrict to local dev.\n\nNotes:\n\n* Node security guidance discusses inspector exposure risks (e.g., DNS rebinding) and recommends not running inspector in production. ([Node.js][15])\n\n---\n\n### EXPRESS-NODE-HTTP-001: Do not enable insecure HTTP parsing in production\n\nSeverity: High\n\nNOTE: Ensure that this detection is actually in the production path, and not just being used for local dev.\n\nRequired:\n\n* MUST NOT use Node’s `insecureHTTPParser` in production.\n* MAY suggest configuring front-end proxies to normalize ambiguous requests to reduce request smuggling risk.\n\nInsecure patterns:\n\n* Creating an HTTP server with `{ insecureHTTPParser: true }`.\n\nDetection hints:\n\n* Search for `insecureHTTPParser` in server creation code.\n\nFix:\n\n* Remove insecure parsing; rely on spec-compliant parsing and normalize at the edge.\n\nNotes:\n\n* Node security guidance explicitly recommends not using `insecureHTTPParser`. ([Node.js][15])\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning an Express repo, these patterns are high-signal:\n\n* TLS / transport:\n\n  * `app.listen(80` without reverse proxy mention; missing `helmet`; cookies missing `secure` ([Express][1]) (NOTE this only applies to web facing applications, internal apps likely won't have TLS)\n* Proxy trust:\n\n  * `app.set('trust proxy', true)`; logic using `req.ip`/`req.protocol`/`req.hostname` ([Express][2])\n* Security headers / fingerprinting:\n\n  * missing `helmet(`; missing `app.disable('x-powered-by')` ([Express][1])\n* Cookies / sessions:\n\n  * `express-session` with missing `store` (MemoryStore risk), hard-coded `secret:`, missing `cookie: { secure/httpOnly/sameSite }` ([Express][1])\n  * `cookie-session` storing large objects or secrets ([Express][1])\n* Body parsing limits:\n\n  * `express.json()` or `express.urlencoded()` without `limit`/`parameterLimit`/`depth` ([Express][5])\n* CSRF:\n\n  * POST/PUT/PATCH/DELETE routes using cookie auth with no CSRF tokens/origin checks ([OWASP Cheat Sheet Series][3])\n* Open redirects:\n\n  * `res.redirect(req.query.next)` or similar ([Express][1])\n* XSS / HTML output:\n\n  * `res.send(` building HTML with user input; template “safe” flags; untrusted values in `res.locals` ([Express][5])\n* File handling:\n\n  * `res.sendFile(` / `res.download(` where path originates from request; `express.static('uploads')` ([Express][5])\n* Injection:\n\n  * SQL strings + template literals into DB calls ([OWASP Cheat Sheet Series][6])\n  * `child_process.exec` / `execSync` / `shell: true` ([OWASP Cheat Sheet Series][14])\n* SSRF:\n\n  * outbound `fetch/axios/got` to user-provided URLs ([OWASP Cheat Sheet Series][7])\n* Brute force / abuse:\n\n  * auth endpoints lacking throttling; no rate limiting middleware ([Express][1])\n* Supply chain:\n\n  * outdated Express versions; no lockfiles; no `npm audit` workflow ([Express][1])\n* Node runtime hazards:\n\n  * `--inspect` in production scripts; `insecureHTTPParser` usage ([Node.js][15])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (HTML/template, SQL/NoSQL, subprocess, filesystem, redirect, outbound HTTP)\n* protective controls present (validation, allowlists, middleware, proxy config, header policies)\n* whether protections are at the edge vs in app code\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary Express documentation:\n\n* Express: Production Best Practices — Security: `https://expressjs.com/en/advanced/best-practice-security.html` ([Express][1])\n* Express: Behind Proxies (`trust proxy`): `https://expressjs.com/en/guide/behind-proxies.html` ([Express][2])\n* Express 5.x API Reference (parsers, static, sendFile, redirect, cookies): `https://expressjs.com/en/5x/api.html` ([Express][5])\n* Express: Error Handling: `https://expressjs.com/en/guide/error-handling.html` ([Express][11])\n\nSession middleware documentation:\n\n* express-session docs (cookie flags, secret rotation, fixation mitigation, MemoryStore warning): `https://expressjs.com/en/resources/middleware/session.html` ([Express][1])\n\nNode.js and npm official references:\n\n* Node.js — Security Best Practices (DoS, proxy guidance, inspector risks, request smuggling notes): `https://nodejs.org/en/learn/getting-started/security-best-practices` ([Node.js][15])\n* npm Docs — `npm audit`: `https://docs.npmjs.com/cli/v9/commands/npm-audit/` ([npm Docs][16])\n\nOWASP Cheat Sheet Series:\n\n* Session Management: `https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][12])\n* CSRF Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][3])\n* XSS Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][4])\n* Input Validation: `https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][17])\n* SQL Injection Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][6])\n* OS Command Injection Defense: `https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][14])\n* SSRF Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][7])\n* File Upload: `https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][13])\n* Unvalidated Redirects: `https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][18])\n* HTTP Headers: `https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][10])\n\nVersioning / advisories:\n\n* Express package version (npm): `https://www.npmjs.com/package/express`\n* Express open redirect advisory (CVE): `https://nvd.nist.gov/vuln/detail/CVE-2024-29041` ([NVD][9])\n\n[1]: https://expressjs.com/en/advanced/best-practice-security.html \"Security Best Practices for Express in Production\"\n[2]: https://expressjs.com/en/guide/behind-proxies.html \"Express behind proxies\"\n[3]: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html \"Cross-Site Request Forgery Prevention - OWASP Cheat Sheet Series\"\n[4]: https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html \"Cross Site Scripting Prevention - OWASP Cheat Sheet Series\"\n[5]: https://expressjs.com/en/5x/api.html \"Express 5.x - API Reference\"\n[6]: https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html \"SQL Injection Prevention - OWASP Cheat Sheet Series\"\n[7]: https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html \"Server Side Request Forgery Prevention - OWASP Cheat Sheet Series\"\n[8]: https://cheatsheetseries.owasp.org/cheatsheets/Nodejs_Security_Cheat_Sheet.html \"Nodejs Security - OWASP Cheat Sheet Series\"\n[9]: https://nvd.nist.gov/vuln/detail/cve-2024-29041?utm_source=chatgpt.com \"CVE-2024-29041 Detail - NVD\"\n[10]: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html \"HTTP Headers - OWASP Cheat Sheet Series\"\n[11]: https://expressjs.com/en/guide/error-handling.html \"Express error handling\"\n[12]: https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html \"Session Management - OWASP Cheat Sheet Series\"\n[13]: https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html \"File Upload - OWASP Cheat Sheet Series\"\n[14]: https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html \"OS Command Injection Defense - OWASP Cheat Sheet Series\"\n[15]: https://nodejs.org/en/learn/getting-started/security-best-practices \"Node.js — Security Best Practices\"\n[16]: https://docs.npmjs.com/cli/v9/commands/npm-audit/ \"npm-audit | npm Docs\"\n[17]: https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html \"Input Validation - OWASP Cheat Sheet Series\"\n[18]: https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html \"Unvalidated Redirects and Forwards - OWASP Cheat Sheet Series\"\n","isInternal":false,"tokens":10932,"sizeBytes":49356},{"name":"javascript-general-web-frontend-security.md","path":"core/skills/builtin/security-best-practices/references/javascript-general-web-frontend-security.md","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/security-best-practices/references/javascript-general-web-frontend-security.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Frontend JavaScript/TypeScript Web Security Spec (Vanilla Browser JS/TS, Modern Browsers)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new frontend JavaScript/TypeScript (no specific framework assumed).\n2. **Security review / vulnerability hunting** in existing frontend code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, hard-code, or commit secrets (API keys intended to be secret, private keys, passwords, OAuth refresh tokens, session tokens, cookies).\n  Notes:\n\n  * Frontend code is inherently observable by end users. If a value must remain secret, it must not be in browser-delivered code.\n  * If the project uses “public” keys (e.g., publishable analytics keys), they MUST be treated as non-secret and scoped accordingly.\n\n* MUST NOT “fix” security by disabling protections (e.g., weakening CSP with `unsafe-inline`/`unsafe-eval` without justification, removing origin checks for `postMessage`, switching to `innerHTML` for convenience, accepting arbitrary redirects/URLs, or turning off sanitization).\n\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and relevant HTML/CSP/config values that justify the claim.\n\n* MUST treat uncertainty honestly:\n\n  * Security headers (CSP, frame-ancestors, etc.) might be set by server/edge/CDN rather than in repo code. If not visible, report as “not visible here; verify at runtime/edge config.” (Also note that `<meta http-equiv=...>` only simulates a subset of headers; don’t assume other security headers exist just because a meta tag exists.) ([MDN Web Docs][1])\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new frontend JS/TS code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default browser APIs and proven libraries over custom security code (especially for HTML sanitization).\n* MUST avoid introducing new risky sinks (DOM XSS injection sinks like `innerHTML`, navigation to `javascript:` URLs, dynamic code execution via `eval`/`Function`, unsafe `postMessage`, unsafe third-party script loading, etc.). ([OWASP Cheat Sheet Series][2])\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a frontend repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. HTML entrypoints (`index.html`, server-rendered templates), script/style includes, and any CSP delivery (header vs meta). ([W3C][3])\n2. DOM XSS sinks (`innerHTML`, `document.write`, `insertAdjacentHTML`, event-handler attributes) and their data sources (URL params/hash, storage, postMessage, API responses). ([OWASP Cheat Sheet Series][2])\n3. Navigation/redirect handling (`window.location*`, link targets, URL allowlists) including `javascript:` URL hazards. ([MDN Web Docs][4])\n4. Cross-origin communication (`postMessage`, iframe embed patterns, sandboxing). ([MDN Web Docs][5])\n5. Storage of sensitive data (localStorage/sessionStorage) and assumptions about trust. ([OWASP Cheat Sheet Series][6])\n6. Third-party scripts / tag managers / CDNs, and integrity controls (SRI) and policy controls (CSP). ([OWASP Cheat Sheet Series][7])\n7. DOM clobbering gadgets and unsafe reliance on `window`/`document` named properties. ([OWASP Cheat Sheet Series][8])\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nExamples include:\n\n* URL-derived data: `location.href`, `location.search`, `location.hash`, `document.baseURI`, `new URLSearchParams(location.search)`, routing fragments. ([OWASP Cheat Sheet Series][2])\n* DOM content that may include user-controlled markup (comments, profiles, CMS content, markdown-to-HTML output, etc.), especially if inserted dynamically. ([OWASP Cheat Sheet Series][2])\n* `postMessage` event data (`event.data`) and metadata (`event.origin`) from other windows/frames. ([MDN Web Docs][5])\n* Browser storage: `localStorage`, `sessionStorage`, IndexedDB (contents can be attacker-influenced via XSS or local machine access; never treat as “trusted”). ([OWASP Cheat Sheet Series][6])\n* Any data returned from network calls (even if from “your API”), because it may contain stored attacker content that becomes dangerous only when inserted into the DOM. ([OWASP Cheat Sheet Series][2])\n\n### 2.2 Dangerous sink (DOM XSS / code execution sink)\n\nA sink is any API/operation that can execute script or interpret attacker-controlled strings as HTML/JS/URL in a security-sensitive way. High-signal sinks include:\n\n* HTML parsing / insertion: `innerHTML`, `outerHTML`, `insertAdjacentHTML`, `document.write`, `document.writeln`. ([OWASP Cheat Sheet Series][2])\n* Dynamic code execution: `eval`, `new Function`, `setTimeout(\"...\")`, `setInterval(\"...\")`. ([MDN Web Docs][10])\n* Navigation to script-bearing URLs (e.g., `javascript:`) via setters like `Location.href`/`window.location` (and via link `href` if attacker-controlled). ([MDN Web Docs][4])\n* Setting event handler attributes from strings, e.g. `setAttribute(\"onclick\", \"...\")`. ([OWASP Cheat Sheet Series][2])\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + function/class/module + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest baseline that prevents common frontend JS/TS security misconfigurations. Some items are “in repo” (HTML/JS) and some may live at the server/edge.\n\n### 3.1 Content Security Policy (CSP) baseline (SHOULD; MUST for high-risk apps)\n\n* SHOULD deliver CSP via HTTP response headers when possible.\n* MAY deliver CSP via an HTML `<meta http-equiv=\"Content-Security-Policy\" ...>` tag when you cannot set headers (e.g., purely static hosting constraints). ([MDN Web Docs][1])\n* If using CSP via `<meta http-equiv>`, MUST understand the limitations:\n\n  * The policy only applies to content that follows the meta element (so it must appear very early, before any scripts/resources you want governed). ([W3C][3])\n  * The following directives are **not supported** in a meta-delivered policy and will be ignored: `report-uri`, `frame-ancestors`, and `sandbox`. ([W3C][3])\n  * “Report-only” CSP cannot be set via a meta element. ([W3C][3])\n\nPractical baseline goals:\n\n* Avoid script sources `unsafe-inline` and `unsafe-eval` (they significantly weaken CSP’s value against XSS). ([MDN Web Docs][10])\n* Prefer nonce- or hash-based script policies if you need inline scripts. ([MDN Web Docs][10])\n* Consider enabling Trusted Types enforcement where feasible. ([MDN Web Docs][11])\n\n### 3.2 Third-party scripts baseline (SHOULD)\n\n* SHOULD minimize third-party script execution and treat it as equivalent privilege to first-party JS (it runs with your origin’s privileges). ([OWASP Cheat Sheet Series][7])\n* SHOULD use Subresource Integrity (SRI) for third-party scripts/styles loaded from CDNs. ([MDN Web Docs][12])\n\n### 3.3 Cross-window communication baseline (SHOULD)\n\n* SHOULD restrict `postMessage` communications to explicit origins, and validate both origin and message shape. ([MDN Web Docs][5])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### JS-XSS-001: Do not inject untrusted HTML into the DOM (avoid `innerHTML` and friends)\n\nSeverity: Critical if you can prove attacker-controlled input can reach these APIs; otherwise Medium\n\n\nRequired:\n\n* MUST treat `innerHTML`, `outerHTML`, and `insertAdjacentHTML` as dangerous sinks when their input can contain untrusted data. ([OWASP Cheat Sheet Series][2])\n* MUST prefer safe DOM APIs that do not parse HTML:\n\n  * `textContent` for text. ([OWASP Cheat Sheet Series][2])\n  * `document.createElement`, `appendChild`, `setAttribute` for non-event-handler attributes. ([OWASP Cheat Sheet Series][2])\n* If HTML insertion is truly required, SHOULD sanitize with a well-reviewed HTML sanitizer and strongly consider enforcing Trusted Types to confine usage to audited code paths. ([MDN Web Docs][11])\n\nInsecure patterns:\n\n* `el.innerHTML = userInput`\n* `el.insertAdjacentHTML('beforeend', userInput)`\n* `el.outerHTML = userInput`\n\nDetection hints:\n\n* Search for: `.innerHTML`, `.outerHTML`, `insertAdjacentHTML(`.\n* Trace the origin of inserted string: URL params/hash, postMessage, storage, API responses, DOM attributes. ([OWASP Cheat Sheet Series][2])\n\nFix:\n\n* Replace with `textContent` for plain text. ([OWASP Cheat Sheet Series][2])\n* For structured UI, build DOM nodes explicitly.\n* For “rich text” requirements:\n\n  * Sanitize using an allowlist-based sanitizer.\n  * Prefer returning safe “components” instead of arbitrary HTML strings.\n  * Use Trusted Types enforcement to ensure only `TrustedHTML` reaches sinks where supported. ([MDN Web Docs][11])\n\nMitigation:\n\n* Deploy a strict CSP and consider Trusted Types enforcement (`require-trusted-types-for 'script'`). ([MDN Web Docs][10])\n\nFalse positive notes:\n\n* If the string is provably constant or fully generated from trusted constants, it may be safe. Still prefer safer APIs.\n\n---\n\n### JS-XSS-002: Avoid `document.write` / `document.writeln` (XSS + document clobbering hazards)\n\nSeverity: Critical if you can prove attacker-controlled input can reach these APIs; otherwise Medium\n\nRequired:\n\n* MUST avoid `document.write()` and `document.writeln()` in production code (they are XSS vectors and can be abused with crafted HTML even if some browsers block injected `<script>` in certain situations). ([MDN Web Docs][13])\n* If legacy use is unavoidable, MUST ensure no untrusted input reaches these APIs and SHOULD enforce Trusted Types (`TrustedHTML`) where supported. ([MDN Web Docs][14])\n\nInsecure patterns:\n\n* `document.write(userInput)`\n* `document.writeln(getParam('q'))`\n\nDetection hints:\n\n* Search for `document.write(`, `document.writeln(`. ([OWASP Cheat Sheet Series][2])\n\nFix:\n\n* Replace with DOM manipulation (`createElement`, `appendChild`) or safe text insertion (`textContent`). ([OWASP Cheat Sheet Series][2])\n\nMitigation:\n\n* Strict CSP + Trusted Types enforcement reduces blast radius if a sink remains. ([MDN Web Docs][10])\n\n---\n\n### JS-XSS-003: Do not use string-to-code execution (`eval`, `new Function`, string timeouts)\n\nSeverity: Critical if you can prove attacker-controlled input can reach these APIs; otherwise Medium\n\nRequired:\n\n* MUST NOT pass untrusted data to:\n\n  * `eval()`\n  * `new Function(...)`\n  * `setTimeout(\"...\")` / `setInterval(\"...\")` with string arguments ([MDN Web Docs][10])\n* SHOULD avoid these APIs entirely in modern frontend code; refactor to non-eval logic. ([MDN Web Docs][10])\n* MUST NOT “fix CSP breakage” by adding `unsafe-eval` unless there is a documented, reviewed justification and compensating controls. ([MDN Web Docs][10])\n\nInsecure patterns:\n\n* `eval(userInput)`\n* `new Function(\"return \" + userInput)()`\n* `setTimeout(userInput, 0)` where userInput is a string\n\nDetection hints:\n\n* Search for `eval(`, `new Function`, `setTimeout(\"`, `setInterval(\"`.\n* Also search for construction of code strings used later.\n\nFix:\n\n* Replace dynamic code with:\n\n  * structured data + explicit branching/handlers,\n  * JSON parsing (`JSON.parse`) instead of `eval` for JSON. ([OWASP Cheat Sheet Series][2])\n\nMitigation:\n\n* CSP that blocks `eval()`-like APIs by default, and avoid `unsafe-eval`. ([MDN Web Docs][10])\n* Consider Trusted Types for controlled cases, but treat it as a hardening layer, not a license to keep eval patterns. ([MDN Web Docs][10])\n\n---\n\n### JS-XSS-004: Do not set event handler attributes from strings (e.g., `setAttribute(\"onclick\", \"...\")`)\n\nSeverity: High\n\nRequired:\n\n* MUST NOT use `setAttribute(\"on…\", string)` or similar patterns with untrusted data; this coerces strings into executable code in the event-handler context. ([OWASP Cheat Sheet Series][2])\n* SHOULD prefer `addEventListener` with function references.\n\nInsecure patterns:\n\n* `el.setAttribute(\"onclick\", userInput)`\n* `el.onclick = userControlledString` (string assignment)\n\nDetection hints:\n\n* Search for `.setAttribute(\"on`, `.onclick =`, `.onmouseover =`, etc.\n* Trace whether RHS can be influenced by URL/hash/storage/postMessage. ([OWASP Cheat Sheet Series][2])\n\nFix:\n\n* Replace with `addEventListener(\"click\", () => { ... })`.\n* If dynamic dispatch is needed, use an allowlisted mapping from identifiers to functions (no string eval). ([OWASP Cheat Sheet Series][2])\n\n---\n\n### JS-URL-001: Sanitize and allowlist URLs before navigation (especially `window.location` / `location.replace`)\n\nSeverity: Low (High if you can prove an attacker can fully control the URL)\n\nIMPORTANT: This can cause a lot of false positives. Please perform extra analysis to determine if the url is fully attacker controlled. If not fully attacker controlled, then this is informational at best.\n\nNOTE: It may be important functionality to be able to redirect to any given url. If that is the goal of the feature, then at a minimum, ensure it checks the schema even if the origin is allowed to be anything.\n\nRequired:\n\n* MUST treat any assignment to navigation targets as security-sensitive:\n\n  * `window.location = ...`\n  * `location.href = ...`\n  * `location.assign(...)`\n  * `location.replace(...)` ([MDN Web Docs][4])\n* MUST prevent navigation to `javascript:` URLs (and generally other script-bearing/active schemes), especially when input is derived from URL params, storage, or messages. ([MDN Web Docs][4]). Only allow `http:` and `https:`.\n* SHOULD validate/allowlist the destination. A safe baseline is:\n\n  * Allow only same-origin relative paths, OR\n  * Allow only a strict allowlist of origins and protocols (typically `https:` and optionally `http:` for localhost dev). ([OWASP Cheat Sheet Series][8])\n\nInsecure patterns:\n\n* `location.replace(getParam(\"next\"))`\n* `window.location = userSuppliedUrl`\n* `location.assign(window.redirectTo || \"/\")` where `redirectTo` can be clobbered or attacker-set ([OWASP Cheat Sheet Series][8])\n\nDetection hints:\n\n* Search for `window.location`, `location.href`, `location.assign`, `location.replace`.\n* Search for common redirect parameters: `next`, `returnTo`, `redirect`, `url`, `continue`.\n* Search for `javascript:` literal usage. ([MDN Web Docs][4])\n\nFix:\n\n* Parse and validate with `new URL(value, location.origin)` and then enforce:\n\n  * `url.protocol` in `{ \"https:\" }` (and only include `http:` in explicit dev-only code paths),\n  * `url.origin` equals `location.origin` for internal redirects, or in a strict allowlist for external redirects,\n  * optionally allow only specific path prefixes. ([MDN Web Docs][4])\n* If validation fails, navigate to a safe default (home/dashboard).\n\nMitigation:\n\n* Deploy strict CSP and Trusted Types enforcement to reduce the impact of DOM XSS sinks, but note that Trusted Types do not prevent every possible unsafe navigation scenario on their own. ([W3C][15])\n\nFalse positive notes:\n\nIMPORTANT: This can cause a lot of false positives. Please perform extra analysis to determine if the url is fully attacker controlled. If not fully attacker controlled, then this is informational at best.\n\n* Some apps intentionally support external redirects (SSO, payment flows). Those MUST be allowlisted and documented.\n\n---\n\n### JS-URL-002: Sanitize URLs before inserting into DOM URL contexts (`href`, `src`, etc.)\n\nSeverity: Low (High if you can prove an attacker can fully control the URL)\n\nIMPORTANT: This can cause a lot of false positives. Please perform extra analysis to determine if the url is fully attacker controlled. If not fully attacker controlled, then this is informational at best.\n\nRequired:\n\n* MUST treat setting URL-bearing DOM attributes/properties as security-sensitive, especially:\n\n  * `a.href`, `img.src`, `script.src`, `iframe.src`, `form.action`, `link.href`.\n* MUST prevent script-bearing schemes (`javascript:` and other active schemes) when values can be attacker-influenced. ([MDN Web Docs][4])\n* SHOULD prefer setting properties (e.g., `a.href = url.toString()`) after parsing and validation, rather than string concatenation.\n\nInsecure patterns:\n\n* `link.href = getParam(\"u\")`\n* `el.setAttribute(\"href\", userInput)` without validation\n* constructing URLs via concatenation with untrusted pieces\n\nDetection hints:\n\n* Search for `.href =`, `.src =`, `.action =`, `setAttribute(\"href\"`, `setAttribute(\"src\"`.\n* Search for `javascript:` / `data:` usage in URLs. ([MDN Web Docs][4])\n\nIMPORTANT: This can cause a lot of false positives. Please perform extra analysis to determine if the url is fully attacker controlled. If not fully attacker controlled, then this is informational at best.\n\nFix:\n\n* Use `new URL(...)` and validate:\n\n  * protocol allowlist\n  * avoid passing user-provided values into `<script src>` at all (treat as code execution). ([OWASP Cheat Sheet Series][8])\n\n---\n\n### JS-CSP-001: Use CSP; meta delivery is allowed\n\nSeverity: Medium to High (depends on threat model; High when handling untrusted content)\n\nNOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n\nRequired:\n\n* SHOULD deploy a CSP as a major defense-in-depth against XSS. ([MDN Web Docs][10])\n* MAY provide CSP via `<meta http-equiv=\"Content-Security-Policy\" ...>` when headers are not available. ([MDN Web Docs][1])\n* If CSP is delivered via meta, MUST:\n\n  * place it early (before scripts/resources you want governed), and\n  * not rely on unsupported directives in meta policies (`report-uri`, `frame-ancestors`, `sandbox`). ([W3C][3])\n* MUST avoid adding `unsafe-inline` as a “quick fix” for CSP issues unless explicitly required and reviewed (it defeats much of CSP’s purpose). ([MDN Web Docs][10])\n* MUST avoid adding `unsafe-eval` unless explicitly required and reviewed (it allows eval-like APIs that are commonly abused). ([MDN Web Docs][10])\n\nInsecure patterns:\n\n* No CSP present anywhere (repo HTML or server/edge) for an app that renders untrusted content.\n* CSP includes `script-src 'unsafe-inline'` and/or `script-src 'unsafe-eval'` without strong justification. ([MDN Web Docs][10])\n* CSP delivered via meta but includes `frame-ancestors` (it will be ignored in meta). ([W3C][3])\n\nDetection hints:\n\n* Search HTML for `<meta http-equiv=\"Content-Security-Policy\"`.\n* Search server/edge configs for `Content-Security-Policy` header.\n* If CSP is only in meta, check it appears before any `<script>` tags you want governed. ([W3C][3])\n\nFix:\n\n* Prefer header-delivered CSP at the server/edge.\n* If constrained to meta, keep a strong allowlist CSP and document the limitations; implement clickjacking protections (e.g., `frame-ancestors`) at the server/edge, not in meta. ([W3C][3])\n\n---\n\n### JS-CSP-002: Prefer strict CSP (nonces/hashes); avoid inline/eval patterns in code\n\nSeverity: Medium\n\nNOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n\nRequired:\n\n* SHOULD design frontend code to work under a strict CSP:\n\n  * avoid inline scripts and inline event handlers,\n  * avoid eval-like APIs (see JS-XSS-003),\n  * allow scripts via nonce or hash when needed. ([MDN Web Docs][10])\n\nInsecure patterns:\n\n* Large amounts of inline script blocks and inline `onclick=\"...\"` handlers.\n* Libraries that require `unsafe-eval`.\n\nDetection hints:\n\n* Search for `<script>` blocks with inline code, `onclick=\"`, `onload=\"`, etc.\n* Search for CSP directives containing `unsafe-inline` or `unsafe-eval`. ([MDN Web Docs][10])\n\nFix:\n\n* Move inline scripts into external JS files (same-origin).\n* Use nonces/hashes for any unavoidable inline blocks. ([MDN Web Docs][10])\n\n---\n\n### JS-TT-001: Use Trusted Types to reduce DOM XSS attack surface (where supported)\n\nSeverity: Low\n\nRequired:\n\n* SHOULD consider enabling Trusted Types enforcement with CSP `require-trusted-types-for 'script'` to make many DOM XSS sinks reject raw strings. ([MDN Web Docs][11])\n* If using Trusted Types, SHOULD also use the CSP `trusted-types` directive to restrict which policies can be created (reduces policy sprawl and improves auditability). ([MDN Web Docs][16])\n* MUST keep Trusted Types policy code small, heavily reviewed, and used as the only path to produce trusted values for sinks. ([W3C][15])\n\nInsecure patterns:\n\n* “Trusted Types enabled” but policy simply returns input unchanged (no sanitization/validation).\n* Many ad-hoc policies created across the codebase without restriction.\n* Belief that Trusted Types alone prevents all unsafe navigations or all XSS classes. (It targets DOM injection sinks; it is not a universal sandbox.) ([W3C][15])\n\nDetection hints:\n\n* Search for CSP directives: `require-trusted-types-for` and `trusted-types`.\n* Search code for `trustedTypes.createPolicy(` and inspect policy implementations. ([MDN Web Docs][11])\n\nFix:\n\n* Add a small set of well-reviewed policies (e.g., `createHTML` that sanitizes).\n* Restrict allowed policies via `trusted-types <policyName...>`.\n* Migrate sinks to require `TrustedHTML` / `TrustedScriptURL` as appropriate. ([MDN Web Docs][11])\n\n---\n\n### JS-MSG-001: `postMessage` must use strict origin validation and explicit targetOrigin\n\nSeverity: Medium (High if dangerous behavior can be triggered via postMessage)\n\nRequired:\n\n* When sending messages, MUST set an explicit `targetOrigin` (not `*`) to avoid sending data to an unexpected origin after redirects or window origin changes. ([MDN Web Docs][5])\n* When receiving messages, MUST:\n\n  * Validate `event.origin` exactly against an allowlist of expected origins (no substring matching). ([OWASP Cheat Sheet Series][6])\n  * Consider validating `event.source` (expected window reference) when applicable. ([MDN Web Docs][5])\n  * Validate `event.data` structure (schema/shape) and treat it purely as data (never evaluate it as code and never insert into DOM with `innerHTML`). ([OWASP Cheat Sheet Series][6])\n\nInsecure patterns:\n\n* `otherWindow.postMessage(payload, \"*\")`\n* `window.addEventListener(\"message\", (e) => { doSomething(e.data) })` with no `origin` check\n* `if (e.origin.includes(\"trusted.com\"))` (substring checks)\n* `el.innerHTML = e.data` ([OWASP Cheat Sheet Series][6])\n\nDetection hints:\n\n* Search for `postMessage(`, `addEventListener(\"message\"`, `onmessage =`.\n* Audit all handlers for explicit allowlist checks on `event.origin`. ([OWASP Cheat Sheet Series][6])\n\nFix:\n\n* Define an allowlist:\n\n  * `const ALLOWED = new Set([\"https://app.example.com\", \"https://accounts.example.com\"]);`\n  NOTE: For ease of development, you can use the current page's origin `window.location.origin` as a safe default origin.\n* On receive:\n\n  * `if (!ALLOWED.has(event.origin)) return;`\n  * Validate `event.data` with a strict schema and reject unknown/extra fields.\n* On send:\n\n  * use the exact expected origin string as `targetOrigin`. ([OWASP Cheat Sheet Series][6])\n\nMitigation:\n\n* Combine with a strict CSP and avoid DOM sinks in message paths. ([MDN Web Docs][10])\n\n---\n\n### JS-STORAGE-001: Web Storage is not a safe place for secrets (and is attacker-influencable)\n\nSeverity: Low\n\nRequired:\n\n* MUST NOT store sensitive secrets or session identifiers in `localStorage` (or `sessionStorage`) if compromise would matter; a single XSS can exfiltrate everything in storage. ([OWASP Cheat Sheet Series][6])\n* MUST treat values read from storage as untrusted input (attackers can load malicious values into storage via XSS). ([OWASP Cheat Sheet Series][6])\n* SHOULD prefer server-set cookies with `HttpOnly` for session identifiers (JS cannot set `HttpOnly`, so avoid storing session IDs in JS-accessible storage). ([OWASP Cheat Sheet Series][6])\n* SHOULD avoid hosting multiple unrelated apps on the same origin if they rely on storage separation (storage is origin-wide). ([OWASP Cheat Sheet Series][6])\n\nInsecure patterns:\n\n* `localStorage.setItem(\"access_token\", token)`\n* `localStorage.setItem(\"session\", sessionId)`\n* Assuming `localStorage` is “trusted because same-origin.”\n\nDetection hints:\n\n* Search for `localStorage.getItem`, `localStorage.setItem`, `sessionStorage.*`.\n* Flag storage keys named `token`, `jwt`, `session`, `auth`, `refresh`. ([OWASP Cheat Sheet Series][6])\n\nFix:\n\n* Use server-managed sessions or short-lived tokens delivered and rotated securely, with careful XSS defenses (CSP/Trusted Types) and minimal JS exposure.\n* If storage must be used for non-sensitive state, keep it non-auth and validate/escape before use.\n\n---\n\n### JS-SUPPLY-001: Third-party JavaScript is a major supply-chain risk; minimize and control it\n\nSeverity: Low\n\nRequired:\n\n* MUST treat third-party JS as equivalent to first-party JS in privilege (it can execute arbitrary code in your origin and access DOM data). ([OWASP Cheat Sheet Series][7])\n* SHOULD minimize third-party scripts and prefer:\n\n  * self-hosting / script mirroring,\n  * strict CSP allowlists,\n  * SRI for any CDN-hosted scripts,\n  * ongoing monitoring for unexpected changes. ([OWASP Cheat Sheet Series][7])\n\nInsecure patterns:\n\n* Loading arbitrary remote scripts from many vendors without review.\n* Using tag managers that can dynamically inject scripts with no integrity controls.\n* Allowing scripts from broad wildcards in CSP (e.g., `script-src *`). ([MDN Web Docs][10])\n\nDetection hints:\n\n* Search HTML for `<script src=\"https://...\">` and `tag manager` snippets.\n* Search CSP `script-src` sources for wildcards or overly broad domains.\n* Search for dynamic script injection: `document.createElement(\"script\")`, `script.src = ...`, `appendChild(script)`. ([OWASP Cheat Sheet Series][8])\n\nFix:\n\n* Remove unnecessary third-party tags.\n* Self-host or mirror scripts where possible.\n* Lock down CSP `script-src` to the smallest set of trusted sources.\n* Add SRI for CDN scripts/styles. ([OWASP Cheat Sheet Series][7])\n\n---\n\n### JS-SRI-001: Use Subresource Integrity (SRI) for third-party scripts/styles\n\nSeverity: Low\n\nRequired:\n\n* SHOULD use SRI to ensure browsers only load third-party resources if they match an expected cryptographic hash. ([MDN Web Docs][12])\n* MUST update SRI hashes whenever the underlying resource changes (pin versions; avoid “latest” URLs).\n\nInsecure patterns:\n\n* `<script src=\"https://cdn.example.com/lib.js\"></script>` with no `integrity`.\n* Loading `latest` or unpinned third-party resources.\n\nDetection hints:\n\n* Search for `<script src=\"https://` and `<link rel=\"stylesheet\" href=\"https://` without `integrity=`.\n* Check whether `integrity` is present and uses strong hashes (sha256/384/512 are typical). ([MDN Web Docs][12])\n\nFix:\n\n* Add `integrity=\"sha384-...\"` (or appropriate) and ensure proper CORS mode where needed.\n* Prefer self-hosting critical libraries.\n\n---\n\n### FS-DOMC-001: Prevent DOM clobbering (avoid relying on `window`/`document` named properties)\n\nSeverity: Medium to High (can become Critical if it enables script loading or `javascript:` navigation)\n\nRequired:\n\n* MUST NOT rely on implicit global variables or `window.someName` / `document.someName` lookups that can be clobbered by injected HTML elements with matching `id`/`name`. ([OWASP Cheat Sheet Series][8])\n* MUST avoid patterns like `let x = window.redirectTo || \"/safe\"; location.assign(x);` where `redirectTo` could be clobbered to an `<a>` element whose `href` is attacker-controlled (including `javascript:`). ([OWASP Cheat Sheet Series][8])\n* SHOULD use explicit variable declarations, local scope, and explicit DOM queries (`getElementById`) rather than named property access. ([OWASP Cheat Sheet Series][8])\n* If the app inserts user-controlled markup (even sanitized), SHOULD ensure sanitization strategies consider `id`/`name` collisions. ([OWASP Cheat Sheet Series][8])\n\nInsecure patterns:\n\n* `const cfg = window.config || {};` used for security-sensitive URLs.\n* `const redirect = window.redirectTo || \"/\"; location.assign(redirect);` ([OWASP Cheat Sheet Series][8])\n* Loading scripts from `window.*` config values without strict validation.\n\nDetection hints:\n\n* Search for `window.` and `document.` used as config stores (especially `||` fallback patterns).\n* Search for usage of `location.assign/replace` with variables that come from `window`/`document` properties.\n* Search for dynamic script creation (`createElement('script')`) where `.src` comes from a non-local variable. ([OWASP Cheat Sheet Series][8])\n\nFix:\n\n* Store config in module-scoped constants (not on `window`/`document`) and pass it explicitly.\n* Validate any URL-like config with protocol/origin allowlists (see FEJS-URL-001). ([OWASP Cheat Sheet Series][8])\n* Consider hardening: sanitization, CSP, and (in limited cases) freezing sensitive objects, but treat these as defense-in-depth, not a substitute for safe coding patterns. ([OWASP Cheat Sheet Series][8])\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* DOM XSS sinks:\n\n  * `.innerHTML`, `.outerHTML`, `insertAdjacentHTML(`\n  * `document.write(`, `document.writeln(` ([OWASP Cheat Sheet Series][2])\n\n* Dangerous navigation / URL sinks:\n\n  * `window.location`, `location.href`, `location.assign`, `location.replace`\n  * `javascript:` literals (and other suspicious schemes like `data:text/html`) ([MDN Web Docs][4])\n\n* String-to-code execution:\n\n  * `eval(`, `new Function`, `setTimeout(\"`, `setInterval(\"` ([MDN Web Docs][10])\n\n* Event-handler string injection:\n\n  * `.setAttribute(\"on`, `.onclick =`, `.onload =` with strings ([OWASP Cheat Sheet Series][2])\n\n* `postMessage`:\n\n  * `postMessage(` with `\"*\"` as targetOrigin\n  * `addEventListener(\"message\"` without strict `event.origin` allowlist checks ([MDN Web Docs][5])\n\n* Storage:\n\n  * `localStorage.setItem(` / `getItem(`, `sessionStorage.*`\n  * keys containing `token`, `jwt`, `session`, `auth`, `refresh` ([OWASP Cheat Sheet Series][6])\n\n* CSP and related:\n\n  * `Content-Security-Policy` header config (server/edge)\n  * `<meta http-equiv=\"Content-Security-Policy\" ...>`\n  * CSP containing `unsafe-inline` or `unsafe-eval`\n  * `require-trusted-types-for` / `trusted-types` directives ([MDN Web Docs][1])\n\n* Third-party scripts:\n\n  * `<script src=\"https://...\">` without `integrity=`\n  * Tag manager snippets and dynamic script injection code paths ([MDN Web Docs][12])\n\n\n* DOM clobbering gadgets:\n\n  * `window.<name> || ...` and `document.<name> || ...` patterns\n  * security-sensitive usage of `window`/`document` properties as config sources ([OWASP Cheat Sheet Series][8])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted),\n* sink type (HTML parse, navigation, code execution, message handling, storage),\n* protective controls present (CSP, Trusted Types, sanitizers, strict allowlists, schema validation).\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary standards / platform docs:\n\n* W3C Content Security Policy Level 2 (HTML `<meta>` delivery restrictions; unsupported directives in meta CSP): `https://www.w3.org/TR/CSP2/` ([W3C][3])\n* MDN: CSP Guide (strict CSP, nonces/hashes, `unsafe-inline`/`unsafe-eval`, eval blocking): `https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP` ([MDN Web Docs][10])\n* MDN: `<meta http-equiv>` (CSP via meta and warning about meta-based security headers): `https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/meta/http-equiv` ([MDN Web Docs][1])\n* MDN: `frame-ancestors` (and note it’s not supported in `<meta>`): `https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/frame-ancestors` ([MDN Web Docs][18])\n\nDOM XSS and dangerous sinks:\n\n* OWASP: DOM Based XSS Prevention Cheat Sheet (dangerous sinks + safe patterns like `textContent`): `https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][2])\n* MDN: `innerHTML` (security considerations): `https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML` ([MDN Web Docs][19])\n* MDN: `insertAdjacentHTML` (security considerations): `https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML` ([MDN Web Docs][20])\n* MDN: `document.write()` / `document.writeln()` (security considerations): `https://developer.mozilla.org/en-US/docs/Web/API/Document/write` and `https://developer.mozilla.org/en-US/docs/Web/API/Document/writeln` ([MDN Web Docs][13])\n\nURL scheme hazards:\n\n* MDN: `javascript:` URLs (execution on navigation; discouraged; references `window.location`): `https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Schemes/javascript` ([MDN Web Docs][4])\n\nTrusted Types:\n\n* W3C: Trusted Types spec (DOM XSS sinks include `Element.innerHTML` and `Location.href` setters; goals and limitations): `https://www.w3.org/TR/trusted-types/` ([W3C][15])\n* MDN: `require-trusted-types-for` directive: `https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/require-trusted-types-for` ([MDN Web Docs][11])\n* MDN: `trusted-types` directive: `https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/trusted-types` ([MDN Web Docs][16])\n\nCross-window messaging:\n\n* MDN: `window.postMessage` (security guidance: specify targetOrigin; validate origin): `https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage` ([MDN Web Docs][5])\n* OWASP: HTML5 Security Cheat Sheet (Web Messaging guidance: explicit origin, strict checks, no `innerHTML`): `https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][6])\n\nThird-party scripts and integrity:\n\n* OWASP: Third Party JavaScript Management Cheat Sheet (risks and mitigations including SRI/mirroring): `https://cheatsheetseries.owasp.org/cheatsheets/Third_Party_Javascript_Management_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][7])\n* MDN: Subresource Integrity overview: `https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity` ([MDN Web Docs][12])\n* W3C: Subresource Integrity spec: `https://www.w3.org/TR/sri-2/` ([W3C][21])\n\nDOM clobbering:\n\n* OWASP: DOM Clobbering Prevention Cheat Sheet (named property access risk; example attacks involving `location.assign` and `javascript:`): `https://cheatsheetseries.owasp.org/cheatsheets/DOM_Clobbering_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][8])\n\n[1]: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/meta/http-equiv \"https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/meta/http-equiv\"\n[2]: https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html\"\n[3]: https://www.w3.org/TR/CSP2/ \"Content Security Policy Level 2\"\n[4]: https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Schemes/javascript \"javascript: URLs - URIs | MDN\"\n[5]: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage \"https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage\"\n[6]: https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html\"\n[7]: https://cheatsheetseries.owasp.org/cheatsheets/Third_Party_Javascript_Management_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Third_Party_Javascript_Management_Cheat_Sheet.html\"\n[8]: https://cheatsheetseries.owasp.org/cheatsheets/DOM_Clobbering_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/DOM_Clobbering_Prevention_Cheat_Sheet.html\"\n[9]: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/noopener \"https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/noopener\"\n[10]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP \"https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP\"\n[11]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/require-trusted-types-for \"https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/require-trusted-types-for\"\n[12]: https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity \"https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity\"\n[13]: https://developer.mozilla.org/en-US/docs/Web/API/Document/write \"https://developer.mozilla.org/en-US/docs/Web/API/Document/write\"\n[14]: https://developer.mozilla.org/en-US/docs/Web/API/Document/writeln \"https://developer.mozilla.org/en-US/docs/Web/API/Document/writeln\"\n[15]: https://www.w3.org/TR/trusted-types/ \"https://www.w3.org/TR/trusted-types/\"\n[16]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/trusted-types \"https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/trusted-types\"\n[18]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/frame-ancestors \"https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/frame-ancestors\"\n[19]: https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML \"https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML\"\n[20]: https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML \"https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML\"\n[21]: https://www.w3.org/TR/sri-2/ \"https://www.w3.org/TR/sri-2/\"\n","isInternal":false,"tokens":9128,"sizeBytes":38637},{"name":"javascript-jquery-web-frontend-security.md","path":"core/skills/builtin/security-best-practices/references/javascript-jquery-web-frontend-security.md","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/security-best-practices/references/javascript-jquery-web-frontend-security.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# jQuery Frontend Security Spec (jQuery 4.0.x, modern browsers)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new jQuery-based frontend code.\n2. **Security review / vulnerability hunting** in existing jQuery-based code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session tokens, refresh tokens, CSRF tokens, session cookies).\n* MUST treat the browser as an attacker-controlled environment:\n\n  * Frontend checks (UI gating, “disable button”, hidden fields, client-side validation) MUST NOT be treated as authorization or a security boundary.\n  * Server-side authorization and validation MUST exist even if frontend is “correct”.\n* MUST NOT “fix” security by disabling protections (e.g., relaxing CSP to allow `unsafe-inline`, enabling JSONP “because it works”, adding broad CORS, disabling sanitization, suppressing security checks).\n* MUST provide evidence-based findings during audits: cite file paths, code snippets, and relevant configuration values.\n* MUST treat uncertainty honestly: if a protection might exist at the edge (CDN/WAF/reverse proxy headers like CSP), report it as “not visible in repo; verify at runtime/config”.\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new jQuery code or modify existing jQuery code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default patterns: text insertion, DOM node construction, allowlists, and proven sanitization libraries over custom escaping.\n* MUST avoid introducing new risky sinks (HTML string building, dynamic script loading, JSONP, inline script/event-handler attributes, unsafe URL assignment, unsafe object merging).\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a repo that uses jQuery (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in the structured format (see §2.3).\n\nRecommended audit order:\n\n1. jQuery sourcing, versions, and dependency hygiene (script tags, lockfiles, CDN usage, SRI).\n2. CSP / Trusted Types / security headers posture (in repo and at runtime if observable).\n3. DOM XSS: untrusted sources → jQuery sinks (`.html`, `.append`, `$(\"<…>\")`, `.load`, etc.).\n4. Script execution sinks: JSONP, `dataType:\"script\"`, `$.getScript`, dynamic `<script>` insertion.\n5. URL/attribute assignment (`href`, `src`, `style`, `on*` attributes).\n6. Prototype pollution / unsafe object merging (`$.extend` patterns).\n7. AJAX auth patterns + CSRF for cookie-based sessions.\n8. Third-party plugins and untrusted content rendering paths (comments, WYSIWYG, markdown-to-HTML).\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nExamples include:\n\n* Any data from the server that originates from users (user profiles, comments, “display name”, rich text, filenames).\n* Data from third-party APIs or services.\n* Browser-controlled sources:\n\n  * `location.href`, `location.search`, `location.hash`\n  * `document.URL`, `document.baseURI`, `document.referrer`\n  * `window.name`\n  * `localStorage` / `sessionStorage`\n  * `postMessage` event data (unless strict origin and schema validation exists)\n  * Any DOM content that could have been injected previously (stored XSS)\n\n### 2.2 High-risk “sinks” in jQuery contexts\n\nA sink is a code path where untrusted input can become interpreted as executable code or HTML.\n\nKey jQuery sink categories:\n\n* HTML insertion / parsing:\n\n  * DOM manipulation methods that accept HTML strings such as `.html()`, `.append()`, and related methods (see CVE notes below). ([NVD][1])\n  * `$(htmlString)` (when the argument can be interpreted as HTML markup).\n  * `jQuery.parseHTML(html, …, keepScripts)` especially with `keepScripts=true`. ([jQuery API][2])\n  * `.load(url)` (loads HTML into DOM; has special script execution behavior). ([jQuery API][3])\n* Script execution / dynamic code loading:\n\n  * `$.getScript()` / `$.ajax({ dataType: \"script\" })` (executes fetched JavaScript). ([jQuery API][4])\n  * JSONP (`dataType: \"jsonp\"` or implicit JSONP behavior) (executes remote JavaScript as a response). ([jQuery API][5])\n  * `eval`, `new Function`, `setTimeout(\"…\")`, `setInterval(\"…\")`, `$.globalEval` (if present)\n* Dangerous attribute assignment:\n\n  * Assigning untrusted strings to `href`, `src`, `srcdoc`, `style`, or event-handler attributes (`onload`, `onclick`, etc.)\n  * `javascript:` URLs are particularly dangerous and discouraged. ([MDN Web Docs][6])\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + function/component + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common jQuery-related security failures.\n\n### 3.1 Use a supported, patched jQuery version (MUST)\n\n* MUST use a supported jQuery major version and keep it updated.\n* As of 2026-01-27, the jQuery project ships jQuery 4.0.0 as the latest major release. ([blog.jquery.com][7])\n* If you must support very old browsers (notably IE < 11), jQuery 4 does not support them and you may need to stay on jQuery 3.x; treat this as a higher risk posture and patch aggressively. ([blog.jquery.com][7])\n\n### 3.2 Load jQuery safely (MUST)\n\n* MUST load jQuery only from:\n\n  * Your own build pipeline (bundled via npm/yarn + lockfile), or\n  * The official jQuery CDN / a trusted CDN with Subresource Integrity (SRI) enabled.\n* If loading from a CDN, SHOULD use SRI (`integrity`) and correct `crossorigin` settings; the jQuery project explicitly supports and recommends SRI on its CDN. (Retrieved from [jquery.com][8])\n\n### 3.3 CSP + Trusted Types (SHOULD, and MUST where available/required by policy)\n\n* SHOULD deploy a Content Security Policy (CSP) that reduces XSS impact (especially `script-src` restrictions and avoiding `unsafe-inline`). If not done through HTTP server, this can be done through the `<meta http-equiv=\"Content-Security-Policy\" content=\"...\">` tag. ([OWASP Cheat Sheet Series][9]) NOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n* SHOULD consider Trusted Types as a strong defense-in-depth against DOM XSS. ([W3C][10])\n* If you deploy the CSP directive `require-trusted-types-for`, then code MUST route DOM-injection through Trusted Types policies. ([MDN Web Docs][11])\n* Note: jQuery 4.0 explicitly added Trusted Types support so that TrustedHTML can be used with jQuery manipulation methods without violating `require-trusted-types-for`. ([blog.jquery.com][7])\n\n### 3.4 Security headers and cookie posture (defense in depth; SHOULD)\n\nEven though these are typically set server-side, they materially reduce the blast radius of jQuery-related mistakes. However if the context is only the frontend web application, these cannot be acted on.\n\n* SHOULD set common security headers (CSP, `X-Content-Type-Options: nosniff`, clickjacking protection via `frame-ancestors` / `X-Frame-Options`, `Referrer-Policy`). ([OWASP Cheat Sheet Series][12])\n* SHOULD avoid storing long-lived secrets/tokens in places accessible to JavaScript (like `localStorage`) unless the threat model explicitly accepts “XSS == account takeover”. This is not jQuery-specific, but jQuery-heavy DOM manipulation increases the chance of DOM XSS regressions; reduce the payoff.\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### JQ-SUPPLY-001: jQuery MUST be patched; do not run known vulnerable versions\n\nSeverity: Medium (High if internet-facing app AND version is known-vulnerable)\n\nNOTE: Before performing an upgrade, get concent from the user and try to understand if they have reasons to keep it back. Upgrading can break applications in unexpected ways. Report and recommend upgrades rather than just performing them.\n\nRequired:\n\n* MUST NOT use jQuery versions with known high-impact vulnerabilities when a patched version exists.\n* MUST upgrade past:\n\n  * CVE-2019-11358 (prototype pollution in jQuery before 3.4.0). ([NVD][13])\n  * CVE-2020-11022 / CVE-2020-11023 (XSS risks in DOM manipulation methods when handling untrusted HTML; patched in 3.5.0). ([NVD][1])\n\nInsecure patterns:\n\n* Script tags or package manifests referencing old jQuery (e.g., `jquery-1.*`, `jquery-2.*`, `jquery-3.3.*`, `jquery-3.4.*`, `jquery-3.4.1`, etc.).\n* Bundled vendor directories containing old minified jQuery without an upgrade path.\n\nDetection hints:\n\n* Search HTML/templates for `jquery-` and parse version strings.\n* Check `package.json`, `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`.\n* Check `vendor/`, `public/`, `static/`, `assets/`, `wwwroot/` for `jquery*.js`.\n\nFix:\n\n* Upgrade to current jQuery (prefer latest stable major; as of 2026-01-27, 4.0.0 is current). ([blog.jquery.com][7])\n* If upgrade is constrained, at minimum upgrade beyond the CVE thresholds and add compensating controls (strong CSP, strict sanitization, remove risky APIs like JSONP, remove deep-extend of untrusted objects).\n\nNotes:\n\n* If a product requirement forces old versions, report as “accepted risk requiring compensating controls”.\n\n---\n\n### JQ-SUPPLY-002: Third-party script loading SHOULD use integrity and trusted origins\n\nSeverity: High\n\nRequired:\n\n* MUST load jQuery and plugins only from trusted origins.\n* If loaded from CDN, SHOULD use SRI (`integrity`) and correct `crossorigin` handling. ([jquery.com][8])\n\nInsecure patterns:\n\n* `<script src=\"https://…/jquery.min.js\"></script>` with no `integrity`.\n* Loading jQuery from random third-party CDNs without an explicit trust decision.\n\nDetection hints:\n\n* Scan HTML for `<script src=` and check for `integrity=` + `crossorigin=`.\n* Identify dynamic script insertion with untrusted URLs (see JQ-EXEC-001).\n\nFix:\n\n* Prefer bundling via npm + lockfile.\n* If using CDN, copy official script tag (jQuery CDN supports SRI). ([jquery.com][8])\n\nNote: If unable to get the correct SRI tag, skip this step but tell the user. If you end up using the wrong one the app will not function. In that case remove it and inform the user.\n\n---\n\n### JQ-XSS-001: Untrusted data MUST NOT be inserted as HTML via jQuery DOM-manipulation methods\n\nSeverity: High (if attacker-controlled content reaches these sinks)\n\nRequired:\n\n* MUST treat any HTML string insertion as a code execution boundary.\n* MUST use safe alternatives for untrusted text:\n\n  * `.text(untrusted)` (text, not HTML). ([jQuery API][14])\n  * `.val(untrusted)` for form fields. ([jQuery API][15])\n  * Create elements and set text/attributes safely instead of concatenating HTML strings.\n\nInsecure patterns (examples):\n\n* `$(selector).html(untrusted)`\n* `$(selector).append(untrusted)`\n* `$(selector).before(untrusted)` / `.after(untrusted)` / `.replaceWith(untrusted)` / `.wrap(untrusted)` (and similar)\n* Building markup: `\"<div>\" + untrusted + \"</div>\"` then passing to jQuery\n\nDetection hints:\n\n* Grep for: `.html(`, `.append(`, `.prepend(`, `.before(`, `.after(`, `.replaceWith(`, `.wrap(`, `.wrapAll(`, `.wrapInner(`\n* Trace dataflow into these calls from sources in §2.1.\n\nFix:\n\n* Replace with `.text()` / `.val()` or node construction:\n\n  * `const $el = $(\"<span>\").text(untrusted); container.append($el);`\n* If the output must contain limited markup, see JQ-XSS-002 (sanitization).\n\nNotes:\n\n* Older jQuery versions had additional edge cases even when attempting sanitization; patched in 3.5.0+. Still: never rely on “string sanitization” alone—prefer structured creation or proven sanitizers. ([GitHub][16])\n\n---\n\n### JQ-XSS-002: If rendering user-controlled HTML is required, it MUST be sanitized with a proven HTML sanitizer\n\nSeverity: Medium (High if rich HTML is attacker-controlled and sanitizer is weak/misconfigured)\n\nRequired:\n\n* MUST NOT “roll your own” HTML sanitizer with regexes.\n* If user-controlled HTML must be displayed (e.g., rich text comments), MUST sanitize using a well-maintained HTML sanitizer and a restrictive allowlist.\n\n  * DOMPurify is a common choice; use conservative configuration and keep it updated. ([GitHub][17])\n  * Where available, MAY consider the browser HTML Sanitizer API (note: limited browser availability). ([MDN Web Docs][18])\n* SHOULD pair sanitization with CSP and, where feasible, Trusted Types for defense in depth. ([OWASP Cheat Sheet Series][9])\n\nInsecure patterns:\n\n* Regex-based “strip `<script>`” or “escape `<`” attempts followed by `.html()` insertion.\n* DOMPurify (or similar) configured to allow overly broad tags/attributes, or configuration that’s not reviewed.\n\nDetection hints:\n\n* Search for “sanitize” helper functions, regex replacing `<`/`>` patterns, or “allow all tags” configs.\n* Identify features that render user-generated “rich text” or “custom HTML”.\n* Check if sanitizer results are inserted with `.html()` or equivalent sinks.\n\nFix:\n\n* Introduce a sanitizer with strict allowlist.\n* Centralize the “sanitize then inject” pattern into a single reviewed module.\n* Add regression tests covering representative malicious inputs (don’t store payloads in logs or telemetry).\n\nFalse positive notes:\n\n* If content is guaranteed trusted (e.g., compiled templates shipped by you), document the trust boundary and why it is not attacker-controlled.\n\n---\n\n### JQ-XSS-003: `$(untrustedString)` and `jQuery.parseHTML` MUST NOT process attacker-controlled markup\n\nSeverity: High (if attacker-controlled)\n\nRequired:\n\n* MUST NOT pass attacker-controlled strings to `$()` when they might be interpreted as HTML.\n* MUST treat `jQuery.parseHTML(html, …, keepScripts)` as a high-risk primitive; keepScripts MUST be `false` for any untrusted input. ([jQuery API][2])\n\nInsecure patterns:\n\n* `const $node = $(untrusted);`\n* `$.parseHTML(untrusted, /* context */, true)` (scripts preserved)\n\nDetection hints:\n\n* Search for `$(` calls where the argument is not a static selector or static markup.\n* Search for `$.parseHTML(` and inspect the `keepScripts` argument.\n\nFix:\n\n* Use DOM creation with constant tag names and `.text()` for untrusted values.\n* If parsing HTML is necessary, sanitize first (JQ-XSS-002) and keep scripts disabled.\n\n---\n\n### JQ-XSS-004: `.load()` MUST be treated as an HTML+script injection surface\n\nSeverity: Medium (High if URL/content is attacker-controlled)\n\nRequired:\n\n* MUST NOT use `.load()` with attacker-controlled URLs or attacker-controlled HTML fragments.\n* MUST understand jQuery `.load()` script behavior:\n\n  * Without a selector in the URL, content is passed to `.html()` before scripts are removed, which can execute scripts. ([jQuery API][3])\n* SHOULD prefer `fetch()`/XHR to retrieve data, then render with safe DOM creation or sanitize explicitly.\n\nInsecure patterns:\n\n* `$(\"#target\").load(untrustedUrl)`\n* `$(\"#target\").load(\"/path?param=\" + untrusted)`\n\nDetection hints:\n\n* Search for `.load(` across JS/TS files.\n* Identify whether a selector is appended to the URL (the behavior differs). ([jQuery API][3])\n* Trace whether the URL can be influenced by user input.\n\nFix:\n\n* Replace `.load()` with:\n\n  * `fetch()` to retrieve JSON, then render via `.text()` / node construction, or\n  * `fetch()` to retrieve HTML, sanitize it, then inject.\n* If `.load()` must remain, ensure the URL is constant or strictly allowlisted and the returned content is trusted.\n\n---\n\n### JQ-EXEC-001: Dynamic script execution and script fetching MUST NOT be reachable from untrusted input\n\nSeverity: High\n\nRequired:\n\n* MUST NOT fetch-and-execute scripts from untrusted or user-influenced URLs.\n* MUST treat these as code execution primitives:\n\n  * `$.getScript(url)` executes the fetched script in the global context. ([jQuery API][4])\n  * `$.ajax({ dataType: \"script\" })` and other script-typed requests that execute responses.\n* SHOULD remove these patterns unless there is a strong, reviewed justification.\n\nInsecure patterns:\n\n* `$.getScript(untrustedUrl)`\n* `$.ajax({ url: untrustedUrl, dataType: \"script\" })`\n* Dynamic `<script src=...>` injection where `src` is derived from untrusted input.\n\nDetection hints:\n\n* Search for `getScript(`, `dataType: \"script\"`, `globalEval`, `eval`, `new Function`.\n* Look for “plugin loader” or “theme loader” features that accept URLs.\n\nFix:\n\n* Bundle scripts at build time.\n* If runtime-loading is required, restrict to allowlisted, versioned, integrity-checked assets (and ideally still avoid runtime code loading).\n\n---\n\n### JQ-AJAX-001: JSONP MUST be disabled unless the endpoint is fully trusted (and even then, avoid)\n\nSeverity: Medium (High if attacker can influence URL/endpoint)\n\nRequired:\n\n* MUST NOT use JSONP for untrusted endpoints because it executes JavaScript responses.\n* When using `$.ajax`, MUST explicitly disable JSONP for non-fully-trusted targets; jQuery’s own docs recommend setting `jsonp: false` “for security reasons” if you don’t trust the target. ([jQuery API][5])\n* SHOULD prefer CORS with JSON (`dataType: \"json\"`) and explicit origin allowlists server-side.\n\nInsecure patterns:\n\n* `dataType: \"jsonp\"`\n* URLs containing `callback=?` or patterns that trigger JSONP behavior. callback arguments are historically XSS vectors.\n* `$.get(untrustedUrl)` without pinning `dataType` and disabling JSONP (risk depends on options and jQuery behavior)\n\nDetection hints:\n\n* Search for `jsonp`, `dataType: \"jsonp\"`, `callback=?`.\n* Search for cross-domain AJAX where the URL is not hard-coded or allowlisted.\n\nFix:\n\n* Use JSON over HTTPS with CORS configured server-side.\n* Set:\n\n  * `dataType: \"json\"`\n  * `jsonp: false` (defense in depth when URL might be ambiguous) ([jQuery API][5])\n\n---\n\n### JQ-AJAX-002: State-changing AJAX requests using cookie auth MUST be CSRF-protected\n\nSeverity: High\n\nNOTE: This only matters when using cookie based auth. If the request use Authorization header, there is no CSRF potential.\n\nRequired:\n\n* If authentication uses cookies, MUST protect state-changing requests (POST/PUT/PATCH/DELETE) against CSRF.\n* SHOULD use server-verified CSRF tokens; for AJAX calls, tokens are commonly sent in a custom header. ([OWASP Cheat Sheet Series][19])\n* MUST NOT treat “it’s an AJAX request” as CSRF protection by itself.\n\nInsecure patterns:\n\n* `$.post(\"/transfer\", {...})` or `$.ajax({ method: \"POST\", ... })` with cookie auth and no CSRF token/header.\n* “CSRF protection” that only checks for `X-Requested-With` (defense-in-depth only, not primary).\n\nDetection hints:\n\n* Enumerate state-changing AJAX calls and locate whether they include CSRF tokens.\n* Identify how the server expects CSRF validation (meta tag, cookie-to-header double submit, synchronizer token, etc.).\n\nFix:\n\n* Add CSRF token inclusion in a centralized place, e.g., `$.ajaxSetup({ headers: { \"X-CSRF-Token\": token } })`, and ensure server verifies.\n* Follow OWASP CSRF guidance for token properties and validation. ([OWASP Cheat Sheet Series][19])\n\nFalse positive notes:\n\n* If auth is not cookie-based (e.g., Authorization header bearer token) CSRF risk is different; verify actual auth mechanism.\n\n---\n\n### JQ-ATTR-001: Untrusted values MUST NOT be written into dangerous attributes without validation/allowlisting\n\nSeverity: Low (High for events like onclick)\n\nRequired:\n\n* MUST validate/allowlist URLs written into `href`, `src`, `action`, etc.\n* MUST block dangerous schemes; `javascript:` URLs are discouraged because they can execute code. ([MDN Web Docs][6])\n* MUST NOT set event-handler attributes (`onclick`, `onerror`, etc.) from strings.\n* SHOULD avoid writing untrusted strings into `style` attributes; prefer toggling predefined CSS classes.\n\nInsecure patterns:\n\n* `$(\"a\").attr(\"href\", untrustedUrl)`\n* `$(\"img\").attr(\"src\", untrustedUrl)`\n* `$(el).attr(\"style\", untrustedCss)`\n* `$(el).attr(\"onclick\", untrustedJs)`\n\nDetection hints:\n\n* Search for `.attr(\"href\"`, `.attr(\"src\"`, `.attr(\"style\"`, `.prop(\"href\"`, `.prop(\"src\"`.\n* Trace whether inputs come from URL params, server JSON, DOM, or storage.\n\nFix:\n\n* Parse and validate URLs with `new URL(value, location.origin)` and allowlist protocols (`https:` etc.) and hostnames when needed.\n* For navigation targets, prefer relative paths you construct rather than full URLs.\n* Replace `style` strings with `addClass/removeClass` using predefined class names.\n\n---\n\n### JQ-SELECTOR-001: User-controlled selector fragments MUST be escaped with `jQuery.escapeSelector`\n\nSeverity: Medium (can become High if it enables wrong-element selection in security-relevant UI)\n\nRequired:\n\n* If you must select by an ID/class that can contain special CSS characters, SHOULD use `jQuery.escapeSelector()` (available in jQuery 3.0+). ([jQuery API][20])\n* MUST NOT concatenate raw attacker-controlled strings into selector expressions.\n\nInsecure patterns:\n\n* `$(\"#\" + untrustedId)`\n* `$(\"[data-id='\" + untrusted + \"']\")` (especially without strict quoting/escaping)\n\nDetection hints:\n\n* Search for `\"#\" +`, `\". \" +`, or template strings used inside `$(` selectors.\n* Look for “select by user-supplied id”.\n\nFix:\n\n* `$(\"#\" + $.escapeSelector(untrustedId))` ([jQuery API][20])\n* Prefer stable internal IDs over user-derived selectors.\n\nNotes:\n\n* This is often “robustness”, but it can become security-relevant if incorrect selection causes UI to reveal/modify the wrong data or skip security-related prompts.\n\n---\n\n### JQ-PROTOTYPE-001: Do not deep-merge untrusted objects; prevent prototype pollution\n\nSeverity: Medium\n\nRequired:\n\n* MUST NOT deep-merge (`$.extend(true, …)`) attacker-controlled objects into application objects without filtering dangerous keys.\n* MUST ensure jQuery is >= 3.4.0 to avoid CVE-2019-11358 prototype pollution behavior. ([NVD][13])\n\nInsecure patterns:\n\n* `$.extend(true, target, untrustedObj)`\n* `$.extend(true, {}, defaults, untrustedObj)` where untrustedObj comes from URL/JSON/storage\n\nDetection hints:\n\n* Search for `$.extend(true` and inspect sources of merged objects.\n* Search for “merge options” / “apply config” patterns using untrusted JSON.\n\nFix:\n\n* Prefer:\n\n  * Shallow merges with an allowlisted set of keys, or\n  * A safe merge helper that explicitly rejects `__proto__`, `prototype`, `constructor`, and nested occurrences.\n* Keep jQuery patched.\n\n---\n\n### JQ-CSP-001: CSP and Trusted Types SHOULD be used to make DOM XSS harder to introduce and exploit\n\nSeverity: Medium\n\nRequired:\n\n* SHOULD deploy CSP as defense-in-depth against XSS. ([OWASP Cheat Sheet Series][9])\n* If enabling Trusted Types (`require-trusted-types-for`), MUST ensure DOM injection goes through Trusted Types policies. ([MDN Web Docs][11])\n* When using jQuery 4, SHOULD take advantage of its Trusted Types support (TrustedHTML inputs). ([blog.jquery.com][7])\n\nInsecure patterns:\n\n* “Fixing” a jQuery feature by weakening CSP (`script-src 'unsafe-inline'` / `'unsafe-eval'`) without a compensating plan.\n* No CSP on applications that render user content or manipulate DOM heavily.\n\nDetection hints:\n\n* Look for CSP headers (server configs, framework middleware, meta tags).\n* If not visible in repo, flag as “verify at edge/runtime”.\n\nFix:\n\n* Add CSP incrementally; start by eliminating inline scripts and inline event handlers, then tighten `script-src`.\n* Add Trusted Types where supported and feasible.\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* jQuery version / sourcing:\n\n  * `jquery-*.js` in `vendor/` or `static/`\n  * `package.json` dependency `jquery` pinned to old versions\n  * CDN script tags lacking `integrity`/`crossorigin` ([jquery.com][8])\n* HTML injection sinks (DOM XSS):\n\n  * `.html(`, `.append(`, `.prepend(`, `.before(`, `.after(`, `.replaceWith(`, `.wrap(`\n  * `$(` where argument might be HTML / template strings\n  * `$.parseHTML(` especially with `keepScripts=true` ([jQuery API][2])\n  * `.load(` (and whether selector is appended; script behavior differs) ([jQuery API][3])\n* Script execution / dynamic code:\n\n  * `$.getScript(`, `dataType: \"script\"` ([jQuery API][4])\n  * `dataType: \"jsonp\"` or `jsonp:` usage; `callback=?` patterns ([jQuery API][5])\n  * `eval`, `new Function`, `setTimeout(\"…\")`, `$.globalEval`\n* Dangerous attribute writes:\n\n  * `.attr(\"href\", …)`, `.attr(\"src\", …)`, `.attr(\"style\", …)`\n  * Any assignment of `javascript:`-like schemes or suspicious URL construction ([MDN Web Docs][6])\n* Selector construction:\n\n  * `$(\"#\" + user)` and similar; fix via `$.escapeSelector` ([jQuery API][20])\n* Prototype pollution:\n\n  * `$.extend(true, …, userObj)`; ensure jQuery >= 3.4.0 and filter dangerous keys ([NVD][13])\n* CSRF posture for AJAX:\n\n  * `$.post(` / `$.ajax({ method: ... })` with cookies and no CSRF token/header ([OWASP Cheat Sheet Series][19])\n* Defense-in-depth:\n\n  * Absence of CSP/security headers in configs (or not visible; require runtime verification) ([OWASP Cheat Sheet Series][12])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (HTML insertion / script execution / attribute / selector / object merge)\n* protective controls present (sanitizer, allowlists, CSP, Trusted Types, CSRF validation)\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary jQuery project documentation and release notes:\n\n* jQuery 4.0.0 release notes (Trusted Types/CSP changes; version info): `https://blog.jquery.com/2026/01/17/jquery-4-0-0/`. ([blog.jquery.com][7])\n* Download jQuery (latest version info; CDN + SRI guidance): `https://jquery.com/download/`. ([jquery.com][8])\n* jQuery API: `.html()`: `https://api.jquery.com/html/`. ([jQuery API][21])\n* jQuery API: `.text()`: `https://api.jquery.com/text/`. ([jQuery API][14])\n* jQuery API: `.append()`: `https://api.jquery.com/append/`. ([jQuery API][22])\n* jQuery API: `.load()` (script execution behavior): `https://api.jquery.com/load/`. ([jQuery API][3])\n* jQuery API: `jQuery.parseHTML(…, keepScripts)`: `https://api.jquery.com/jQuery.parseHTML/`. ([jQuery API][2])\n* jQuery API: `$.ajax()` (`jsonp: false` security note): `https://api.jquery.com/jQuery.ajax/`. ([jQuery API][5])\n* jQuery API: `$.getScript()` (executes script): `https://api.jquery.com/jQuery.getScript/`. ([jQuery API][4])\n* jQuery API: `jQuery.escapeSelector()`: `https://api.jquery.com/jQuery.escapeSelector/`. ([jQuery API][20])\n\njQuery vulnerabilities / advisories:\n\n* NVD CVE-2019-11358 (prototype pollution; jQuery < 3.4.0): `https://nvd.nist.gov/vuln/detail/CVE-2019-11358`. ([NVD][13])\n* NVD CVE-2020-11022 (XSS risk in DOM manipulation methods; patched in 3.5.0): `https://nvd.nist.gov/vuln/detail/CVE-2020-11022`. ([NVD][1])\n* NVD CVE-2020-11023 (XSS risk involving `<option>`; patched in 3.5.0): `https://nvd.nist.gov/vuln/detail/CVE-2020-11023`. ([NVD][23])\n* GitHub Security Advisory GHSA-gxr4-xjj5-5px2 (jQuery htmlPrefilter XSS; patched in 3.5.0): `https://github.com/jquery/jquery/security/advisories/GHSA-gxr4-xjj5-5px2`. ([GitHub][16])\n\nOWASP Cheat Sheet Series (web app security foundations relevant to jQuery usage):\n\n* XSS Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html`. ([OWASP Cheat Sheet Series][24])\n* DOM-based XSS Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html`. ([OWASP Cheat Sheet Series][25])\n* CSRF Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html`. ([OWASP Cheat Sheet Series][19])\n* HTTP Security Headers: `https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html`. ([OWASP Cheat Sheet Series][12])\n* Content Security Policy Cheat Sheet: `https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html`. ([OWASP Cheat Sheet Series][9])\n\nBrowser/platform references (SRI, CSP, Trusted Types, and dangerous URL schemes):\n\n* MDN: Subresource Integrity (SRI): `https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity`. ([MDN Web Docs][26])\n* W3C: SRI specification: `https://www.w3.org/TR/sri-2/`. ([W3C][27])\n* MDN: CSP guide: `https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP`. ([MDN Web Docs][28])\n* MDN: `require-trusted-types-for` directive: `https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/require-trusted-types-for`. ([MDN Web Docs][11])\n* MDN: Trusted Types API: `https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API`. ([MDN Web Docs][29])\n* W3C: Trusted Types specification: `https://www.w3.org/TR/trusted-types/`. ([W3C][10])\n* MDN: `javascript:` URL scheme warning: `https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Schemes/javascript`. ([MDN Web Docs][6])\n* DOMPurify project documentation: `https://github.com/cure53/DOMPurify`. ([GitHub][17])\n\n[1]: https://nvd.nist.gov/vuln/detail/cve-2020-11022?utm_source=chatgpt.com \"CVE-2020-11022 Detail - NVD\"\n[2]: https://api.jquery.com/jQuery.parseHTML/?utm_source=chatgpt.com \"jQuery.parseHTML()\"\n[3]: https://api.jquery.com/load/?utm_source=chatgpt.com \".load() | jQuery API Documentation\"\n[4]: https://api.jquery.com/jQuery.getScript/?utm_source=chatgpt.com \"jQuery.getScript()\"\n[5]: https://api.jquery.com/jQuery.ajax/?utm_source=chatgpt.com \"jQuery.ajax()\"\n[6]: https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Schemes/javascript?utm_source=chatgpt.com \"javascript: URLs - URIs - MDN Web Docs\"\n[7]: https://blog.jquery.com/2026/01/17/jquery-4-0-0/ \"jQuery 4.0.0 | Official jQuery Blog\"\n[8]: https://jquery.com/download/ \"Download jQuery | jQuery\"\n[9]: https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html?utm_source=chatgpt.com \"Content Security Policy - OWASP Cheat Sheet Series\"\n[10]: https://www.w3.org/TR/trusted-types/?utm_source=chatgpt.com \"Trusted Types\"\n[11]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/require-trusted-types-for?utm_source=chatgpt.com \"Content-Security-Policy: require-trusted-types-for directive\"\n[12]: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html?utm_source=chatgpt.com \"HTTP Security Response Headers Cheat Sheet\"\n[13]: https://nvd.nist.gov/vuln/detail/cve-2019-11358?utm_source=chatgpt.com \"CVE-2019-11358 Detail - NVD\"\n[14]: https://api.jquery.com/text/?utm_source=chatgpt.com \".text() | jQuery API Documentation\"\n[15]: https://api.jquery.com/val/?utm_source=chatgpt.com \".val() | jQuery API Documentation\"\n[16]: https://github.com/jquery/jquery/security/advisories/GHSA-gxr4-xjj5-5px2 \"Potential XSS vulnerability in jQuery.htmlPrefilter and related methods · Advisory · jquery/jquery · GitHub\"\n[17]: https://github.com/cure53/DOMPurify?utm_source=chatgpt.com \"DOMPurify - a DOM-only, super-fast, uber-tolerant XSS ...\"\n[18]: https://developer.mozilla.org/en-US/docs/Web/API/HTML_Sanitizer_API?utm_source=chatgpt.com \"HTML Sanitizer API - MDN Web Docs\"\n[19]: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html?utm_source=chatgpt.com \"Cross-Site Request Forgery Prevention Cheat Sheet\"\n[20]: https://api.jquery.com/jQuery.escapeSelector/?utm_source=chatgpt.com \"jQuery.escapeSelector()\"\n[21]: https://api.jquery.com/html/?utm_source=chatgpt.com \".html() | jQuery API Documentation\"\n[22]: https://api.jquery.com/append/?utm_source=chatgpt.com \".append() | jQuery API Documentation\"\n[23]: https://nvd.nist.gov/vuln/detail/cve-2020-11023?utm_source=chatgpt.com \"CVE-2020-11023 Detail - NVD\"\n[24]: https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html?utm_source=chatgpt.com \"Cross Site Scripting Prevention - OWASP Cheat Sheet Series\"\n[25]: https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html?utm_source=chatgpt.com \"DOM based XSS Prevention Cheat Sheet\"\n[26]: https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity?utm_source=chatgpt.com \"Subresource Integrity - Security - MDN Web Docs\"\n[27]: https://www.w3.org/TR/sri-2/?utm_source=chatgpt.com \"Subresource Integrity\"\n[28]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP?utm_source=chatgpt.com \"Content Security Policy (CSP) - HTTP - MDN Web Docs\"\n[29]: https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API?utm_source=chatgpt.com \"Trusted Types API - MDN Web Docs\"\n","isInternal":false,"tokens":8234,"sizeBytes":33581},{"name":"javascript-typescript-nextjs-web-server-security.md","path":"core/skills/builtin/security-best-practices/references/javascript-typescript-nextjs-web-server-security.md","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/security-best-practices/references/javascript-typescript-nextjs-web-server-security.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Next.js (TypeScript/JavaScript) Web Security Spec (Next.js 16.1.x, Node.js 20.9+)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new Next.js backend code (Route Handlers, API Routes, Server Actions, Proxy/Middleware).\n2. **Security review / vulnerability hunting** in existing Next.js repos (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\nTarget scope: Next.js **16.1.x** (latest line shown in the App Router docs) ([Next.js][1]), running on Node.js **20.9+** (per Next.js system requirements). ([Next.js][2])\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session cookies, OAuth tokens, `process.env` dumps, database URLs with credentials).\n* MUST NOT “fix” security by disabling protections (e.g., disabling origin checks, relaxing CORS to `*`, skipping authz checks, turning off cookie security flags, turning off CSP because it’s “hard”).\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and configuration values that justify each claim.\n* MUST treat uncertainty honestly: if a protection might exist in infrastructure (reverse proxy, CDN, WAF, platform headers), report it as “not visible in app code; verify at runtime/config”.\n* MUST assume all request-facing server code is reachable by attackers unless there is a clearly enforced auth boundary (not just “the UI doesn’t link to it”).\n* MUST treat TypeScript types as **non-security boundaries**: types do not validate runtime input; runtime checks are required. ([Next.js][3])\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new Next.js code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default APIs and proven libraries over custom security code.\n* MUST avoid introducing new risky sinks (dynamic code execution, unsafe redirects, serving user files as HTML, SSRF URL fetchers, building SQL strings, etc.).\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a Next.js repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. Deployment entrypoints and environment (Dockerfiles, `package.json` scripts, hosting config).\n2. Next.js config (`next.config.*`), Proxy/Middleware, routing patterns.\n3. Authentication, sessions, cookies.\n4. CSRF protections and state-changing endpoints (Server Actions, Route Handlers, API Routes).\n5. XSS (React + CSP) and unsafe HTML rendering.\n6. Cache/data-leak hazards (static rendering + caching + “use cache”).\n7. File handling (uploads/downloads) and path traversal.\n8. Injection classes (SQL/ORM misuse, command execution, unsafe deserialization).\n9. Outbound requests (SSRF).\n10. Redirect handling (open redirects).\n11. CORS and security headers.\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nIn Next.js backends, untrusted input includes:\n\nApp Router:\n\n* Route Handler params and request data:\n\n  * `context.params` (dynamic segments), search params (`request.url`, `new URL(request.url).searchParams`)\n  * `request.headers`, `request.cookies`\n  * `await request.json()`, `await request.formData()`, `await request.text()`\n* Dynamic APIs used in Server Components/Server Functions:\n\n  * `headers()` and `cookies()` values ([Next.js][4])\n\nPages Router:\n\n* `req.query`, `req.cookies`, `req.body` in `pages/api/*` handlers ([Next.js][3])\n\nPlus:\n\n* Anything from external systems (webhooks, third-party APIs, message queues)\n* Any persisted user content (DB rows) that originated from users\n\n### 2.2 State-changing request\n\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook send), or initiate privileged actions.\n\nSpecial note for Next.js:\n\n* **Server Actions** are invoked via network requests and can mutate state; treat them as state-changing endpoints. ([Next.js][5])\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + function/route name + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common Next.js backend misconfigurations.\n\n### 3.1 Run Next.js in production mode (MUST)\n\n* MUST run `next build` + `next start` (or the managed platform equivalent), not `next dev`. Dev mode has different error/reporting behavior and is not designed for production exposure. ([Next.js][6])\n* MUST ensure `NODE_ENV=production` in production (Next.js defaults `NODE_ENV` based on command; verify the runtime environment). ([Next.js][7])\n\n### 3.2 Put a reverse proxy / edge layer in front when self-hosting (MUST for public internet)\n\n* If self-hosting, MUST place a reverse proxy (e.g., nginx) or equivalent edge layer in front of the Next.js server to handle malformed requests, slow attacks, payload size limits, rate limiting, and similar concerns. ([Next.js][8])\n\n### 3.3 Baseline header/cookie posture (SHOULD)\n\n* SHOULD set a baseline of security headers globally (CSP, `X-Content-Type-Options`, clickjacking defense via CSP `frame-ancestors` and/or `X-Frame-Options`, etc.). Next.js provides guidance for implementing CSP via Proxy/headers. ([Next.js][7])\n* MUST ensure auth/session cookies use secure attributes (`Secure`, `HttpOnly`, `SameSite`) as appropriate. ([Next.js][9])\nIMPORTANT NOTE: Only set `Secure` in production environment. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n\n### 3.4 Clear separation between server-only and client code (MUST)\n\n* MUST prevent secrets and privileged logic from being bundled into client code.\n* MUST treat `NEXT_PUBLIC_*` environment variables as public (browser-exposed and inlined at build time). ([Next.js][7])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### NEXT-DEPLOY-001: Do not run `next dev` in production; ensure production mode behavior\n\nSeverity: High (if production)\n\nNOTE: If they are deploying to a specific Next.js hosting provider, they do not need to worry about this.\n\nRequired:\n\n* MUST NOT deploy `next dev` or any development server mode to production.\n* MUST ensure production builds and production runtime are used for any public deployment. ([Next.js][6])\n\nInsecure patterns:\n\n* `next dev` in Docker `CMD`, Procfile, platform start command.\n* `NODE_ENV=development` in production environment config.\n* Debug/dev-only endpoints or flags exposed publicly.\n\nDetection hints:\n\n* Search `package.json` scripts and deployment manifests for `next dev`.\n* Search infra for `NODE_ENV=development` or missing `NODE_ENV`.\n* Check Kubernetes/PM2/systemd entrypoints for `next dev`.\n\nFix:\n\n* Use `next build` during CI/build and `next start` at runtime (or platform-native build/run).\n* Ensure environment sets `NODE_ENV=production`.\n\nNote:\n\n* Dev mode is fine for local development. Only flag if it is being used as a production entrypoint.\n\n---\n\n### NEXT-SUPPLY-001: Stay on supported Next.js releases; patch quickly for security advisories\n\nSeverity: High (Critical if known-vulnerable version)\n\nRequired:\n\n* MUST run a supported Next.js version line and apply security updates promptly. Next.js documents an LTS/support policy. ([Next.js][10])\n* MUST treat published advisories as urgent upgrade signals (e.g., update to a patched release). ([GitHub][11])\n\nInsecure patterns:\n\n* Running EOL Next.js major/minor without backported security fixes.\n* Ignoring advisories, or pinning `next` to a vulnerable range.\n\nDetection hints:\n\n* Check `package.json` and lockfiles for `next` version.\n* Compare against Next.js support policy and advisories.\n\nIMPORTANT: Any versions older than these minor versions are vulnerable to \"react2shell\" vulnerability (https://nextjs.org/blog/CVE-2025-66478):\n15.0.5\n15.1.9\n15.2.6\n15.3.6\n15.4.8\n15.5.7\n16.0.7\n\nFix:\n\n* Upgrade `next` to a supported and patched version.\n* Add a dependency update process + CI checks.\n\n\n---\n\n### NEXT-SECRETS-001: Secrets MUST NOT be committed or exposed to the browser\n\nSeverity: High (Critical if secret is client-exposed)\n\nRequired:\n\n* MUST store secrets in environment variables or a secret manager; MUST NOT commit `.env*` files.\n* MUST treat `.env*` as sensitive; Next.js warns you “almost never want to commit these files.” ([Next.js][7])\n* MUST treat any `NEXT_PUBLIC_*` environment variable as public and browser-visible (inlined into the client bundle at build time). ([Next.js][7])\n\nInsecure patterns:\n\n* `.env`, `.env.local`, `.env.production` committed to git.\n* `NEXT_PUBLIC_API_KEY`, `NEXT_PUBLIC_SECRET`, `NEXT_PUBLIC_DATABASE_URL`, etc.\n* Rendering `process.env` values into HTML or returning them from API routes.\n\nDetection hints:\n\n* Scan git history and repo files for `.env` content, `DB_PASS=`, `API_KEY=`, `SECRET=`.\n* Grep for `NEXT_PUBLIC_` and review any sensitive-looking names.\n* Search for `process.env` usage in Client Components (`\"use client\"`) and shared modules.\n\nFix:\n\n* Move secrets to server-only env vars (no `NEXT_PUBLIC_` prefix).\n* Ensure `.env*` is ignored and secrets are injected at deploy time.\n* Rotate leaked keys.\n\n---\n\n### NEXT-SECRETS-002: Avoid server-only → client bundling mistakes (server/client boundary is a security boundary)\n\nSeverity: High\n\nRequired:\n\n* MUST ensure server-only modules (DB clients, secret-dependent code) are not imported into Client Components or other client-bundled code paths.\n* SHOULD use server-only patterns/layers (e.g., a dedicated DAL and server-only modules) and treat boundary violations as security bugs. Next.js explicitly discusses the “server-only” concept for sensitive modules. ([Next.js][6])\n\nInsecure patterns:\n\n* Importing DB clients, admin SDKs, or secret-reading modules into `\"use client\"` components.\n* Shared `lib/` modules imported by both server and client code that reference secrets.\n\nDetection hints:\n\n* Search for `\"use client\"` and examine its imports for server-only dependencies.\n* Look for DB client packages (`pg`, `mysql2`, `mongoose`, `prisma`, admin SDKs) imported from `components/` or other client paths.\n* Search for `process.env` access in UI components.\n\nFix:\n\n* Refactor into `lib/server/*` and only import from server contexts (Route Handlers, Server Components, Server Actions).\n* Add an explicit “server-only” guard pattern (and/or tests) to prevent accidental imports.\n\n---\n\n### NEXT-AUTH-001: Authentication/authorization MUST be enforced server-side for every protected action\n\nSeverity: High\n\nRequired:\n\n* MUST enforce authn/authz in server-side code for:\n\n  * Route Handlers (`app/**/route.ts`) ([Next.js][1])\n  * API Routes (`pages/api/**`) ([Next.js][3])\n  * Server Actions (`\"use server\"` functions invoked by clients) ([Next.js][6])\n* MUST NOT rely on client-side checks (hiding UI, route guards on the client) as the only protection.\n\nInsecure patterns:\n\n* Sensitive Route Handlers with no session verification.\n* Server Actions that mutate data but do not validate user identity/permissions.\n* “Authorization” checks in React components only.\n\nDetection hints:\n\n* Enumerate all Route Handlers and API Routes; for each, identify whether it requires auth.\n* Grep for `\"use server\"` and review all exported actions for auth checks.\n* Search for admin actions triggered by query params / form submits.\n\nFix:\n\n* Centralize auth helpers and call them in every protected endpoint/action.\n* Implement least-privilege authorization checks (role/resource ownership) per action.\n\n---\n\n### NEXT-AUTH-002: Proxy/Middleware-based auth MUST NOT create route coverage gaps\n\nSeverity: High\n\nRequired:\n\n* If using **Proxy** or **Middleware** for authentication checks, MUST ensure it covers every route that needs protection.\n* Next.js documentation notes Proxy can use a `matcher`, and for auth it’s recommended Proxy runs on all routes. ([Next.js][12])\n* MUST treat `matcher` mistakes as an auth bypass risk.\n\nInsecure patterns:\n\n* Proxy/Middleware only matches “pages” but not `/api/*`, or only matches some route groups.\n* “Denylist” style matchers that miss alternative request forms (framework-internal variants, RSC navigations, etc.).\n\nDetection hints:\n\n* Inspect `proxy.ts` / `middleware.ts` and its `matcher`.\n* Compare matchers to the full set of routes (including `app/api/**` and `pages/api/**`).\n* Ensure static assets and Next internals are excluded only intentionally, and that sensitive routes are included.\n\nFix:\n\n* Prefer allowlisting protected route prefixes or running Proxy globally and doing internal allow/deny logic.\n* Add integration tests: request protected route without auth and assert denial.\n\nNotes:\n\n* Proxy is commonly used for “optimistic checks”; it is not a complete authorization system by itself. ([Next.js][12])\n\n---\n\n### NEXT-CSRF-001: Cookie-authenticated state-changing endpoints MUST be CSRF-protected\n\nSeverity: High\n\n- IMPORTANT NOTE: If cookies are not being used for auth (ie auth is via Authentication header or other passed token), then there is no CSRF risk.\n\nRequired:\n\n* MUST protect every state-changing endpoint that relies on cookies for auth (POST/PUT/PATCH/DELETE).\n* For **Server Actions**, Next.js performs an Origin/Host comparison to help prevent CSRF; do not disable or weaken it. ([Next.js][5])\n* If Server Actions must be callable from additional trusted origins (e.g., a trusted proxy domain), MUST use `allowedOrigins` with a strict allowlist. ([Next.js][5])\n* For **Route Handlers** and **API Routes**, MUST implement CSRF protections explicitly (tokens and/or strict Origin/Referer + SameSite + custom headers). Route Handlers are an “escape hatch” and require application-level security decisions. ([Next.js][6])\n\nInsecure patterns:\n\n* POST endpoints (including Server Actions) that mutate state and accept cross-site requests with no token/origin checks.\n* `allowedOrigins: ['*']` (or broad wildcards) or “reflect Origin” logic.\n* Using GET requests to change state.\n\nDetection hints:\n\n* Enumerate all state-changing endpoints and determine auth mechanism.\n* Search for `allowedOrigins` and confirm the list is small, specific, and justified. ([Next.js][5])\n* In Route Handlers/API Routes: look for missing CSRF token validation or missing Origin/Referer checks.\n\nFix:\n\n* Implement a CSRF token strategy for cookie-auth endpoints.\n* Keep cookies `SameSite=Lax` or `Strict` when compatible; don’t treat SameSite alone as sufficient.\n* Use strict Origin validation for JSON API endpoints, especially when not using CSRF tokens.\n\nNotes:\n\n* XSS can defeat CSRF protections; CSRF defenses do not replace XSS prevention.\n\n---\n\n### NEXT-SESS-001: Session cookies MUST use secure attributes in production\n\nSeverity: Medium\n\nRequired (production, HTTPS):\n\n* MUST set session/auth cookies with:\n\n  * `Secure: true` (HTTPS-only) IMPORTANT NOTE: Only set `Secure` in production environment. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n  * `HttpOnly: true` (not readable by JS)\n  * `SameSite: 'Lax'` (recommended) or `'Strict'` if compatible\n* Only use `SameSite: 'none'` when you truly need cross-site cookies, and then MUST also set `Secure`. Cookie options are supported in Next.js cookie APIs. ([Next.js][9])\n\nInsecure patterns:\n\n* `secure: false` in production.\n* `httpOnly: false` for auth cookies.\n* `sameSite: 'none'` without a clear need, especially on cookie-authenticated state-changing endpoints.\n\nDetection hints:\n\n* Search for cookie setting sites (`cookies().set(...)`, `Set-Cookie` headers, auth library cookie config).\n* Review cookie options used in Route Handlers and Server Actions. ([Next.js][9])\n\nFix:\n\n* Set secure cookie attributes at the auth/session layer.\n* Reduce cookie scope: avoid wide `domain` unless you explicitly need subdomain-wide cookies.\n\n---\n\n### NEXT-SESS-002: Sessions MUST be bounded and resistant to fixation/replay\n\nSeverity: Low\n\nRequired:\n\n* SHOULD set bounded session lifetimes appropriate to the app.\n* SHOULD rotate session identifiers on login and privilege changes.\n* MUST NOT store sensitive secrets directly in client-readable storage (including cookies that are not encrypted).\n\nInsecure patterns:\n\n* Long-lived admin sessions with no rotation.\n* “Remember me forever” for privileged roles without additional risk controls.\n* Storing access tokens/refresh tokens in non-HttpOnly cookies or localStorage.\n\nDetection hints:\n\n* Review auth library configuration for expiration and rotation.\n* Search for `localStorage.setItem('token'...)` and non-HttpOnly cookie usage.\n\nFix:\n\n* Use short lifetimes for privileged sessions; refresh with rotation.\n* Store only opaque session IDs in cookies; keep sensitive material server-side.\n\n---\n\n### NEXT-INPUT-001: Runtime input validation is mandatory (TypeScript is not validation)\n\nSeverity: High\n\nRequired:\n\n* MUST validate and normalize all attacker-controlled input at runtime (schemas, type checks, bounds).\n* Next.js API Routes explicitly note `req.body` is `any` and must be validated before use. ([Next.js][3])\n* MUST validate Server Action arguments (treat as hostile). ([Next.js][6])\n\nInsecure patterns:\n\n* Trusting `req.body` shape directly.\n* Passing `params.id`/`searchParams` directly into DB queries or file paths.\n* Parsing JSON and then assuming types without validation.\n\nDetection hints:\n\n* Identify endpoints that accept JSON/form input and check for schema validation.\n* Grep for `req.body.` usage and for `await request.json()` usage in Route Handlers; verify validation exists.\n\nFix:\n\n* Add schema validation (e.g., zod/yup/valibot) and reject invalid input with 4xx.\n* Validate IDs as strict types (UUID/int) and enforce length/charset constraints.\n\n---\n\n### NEXT-HEADERS-001: Essential security headers MUST be set (in app or at the edge)\n\nSeverity: Low\n\nRequired (typical web app):\n\n* SHOULD set:\n\n  * CSP (`Content-Security-Policy`) (see NEXT-CSP-001)\n  * `X-Content-Type-Options: nosniff`\n  * Clickjacking defense (`frame-ancestors` in CSP and/or `X-Frame-Options`)\n  * `Referrer-Policy` and `Permissions-Policy` when appropriate\n* MUST ensure cookies are set with secure attributes (see NEXT-SESS-001). ([Next.js][9])\n\nInsecure patterns:\n\n* No security headers anywhere (app or edge).\n* Allowing iframing unintentionally.\n* `Content-Type` sniffing possible due to missing `nosniff`.\n\nDetection hints:\n\n* Check `proxy.ts` / middleware for `response.headers.set(...)`. ([Next.js][7])\n* If not visible in app code, flag as “verify at edge/CDN”.\n\nFix:\n\n* Set headers centrally (Proxy/Middleware or other centralized mechanism).\n* Ensure consistent headers across routes.\n\n---\n\n### NEXT-CSP-001: Use a CSP to reduce XSS impact; prefer nonces for scripts\n\nSeverity: Medium\n\nNOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n\nRequired:\n\n* SHOULD deploy a CSP, ideally with nonces for scripts.\n* SHOULD follow Next.js guidance for CSP implementation (including nonce generation and header application). ([Next.js][7])\n* MUST avoid loosening CSP as a “fix” (e.g., `script-src 'unsafe-inline'`) without explicit risk acceptance.\n\nInsecure patterns:\n\n* CSP missing on apps that display user-generated HTML/markdown.\n* CSP that broadly enables inline scripts or eval without strict justification.\n\nDetection hints:\n\n* Search for `Content-Security-Policy` header setting and examine its directives.\n* Check use of `next/script` and whether a nonce is provided when CSP requires it.\n\nFix:\n\n* Implement CSP per Next.js guidance; use a nonce and apply it consistently.\n* Reduce inline scripts; avoid `eval`.\n\nNotes:\n\n* CSP is defense-in-depth; it does not replace proper output encoding and sanitization.\n\n---\n\n### NEXT-XSS-001: Prevent reflected/stored XSS in React/Next rendering\n\nSeverity: High\n\nRequired:\n\n* MUST rely on React’s default escaping; MUST NOT insert untrusted HTML into the DOM without sanitization.\n* MUST treat these as high-risk sinks:\n\n  * `dangerouslySetInnerHTML`\n  * rendering user-controlled strings into `<script>` tags or event handler attributes\n* MUST avoid serving uploaded HTML as active HTML (serve as attachment or sanitize/transform).\n\nInsecure patterns:\n\n* `<div dangerouslySetInnerHTML={{ __html: userContent }} />` with no sanitizer.\n* Markdown renderers configured to allow raw HTML with no sanitizer.\n* Returning user content with `Content-Type: text/html` from a Route Handler.\n\nDetection hints:\n\n* Search for `dangerouslySetInnerHTML`, `__html:`.\n* Search for template-like string concatenation that builds HTML.\n* Review any “render HTML” or “preview” features.\n\nFix:\n\n* Sanitize untrusted HTML with a well-maintained sanitizer; prefer strict allowlists.\n* Prefer rendering user content as text, not HTML.\n* Add CSP to reduce impact.\n\n---\n\n### NEXT-ACTION-001: Server Actions MUST be treated like public endpoints\n\nSeverity: High (Critical for privileged actions)\n\nRequired:\n\n* MUST apply the same controls as for Route Handlers:\n\n  * authn/authz\n  * input validation\n  * CSRF/origin protections\n  * rate limiting for sensitive actions\n* MUST NOT assume Server Actions are “not reachable” or “internal”.\n* MUST understand Server Action request protections:\n\n  * Next.js compares Origin with host to mitigate CSRF; extra origins must be explicitly allowlisted via `allowedOrigins`. ([Next.js][5])\n\nInsecure patterns:\n\n* `\"use server\"` functions that update DB state with no auth check.\n* Adding overly broad `allowedOrigins` to “make it work”.\n\nDetection hints:\n\n* Grep for `\"use server\"` and inventory all exported actions.\n* Identify any action doing privileged writes; confirm it checks identity and permission.\n\nFix:\n\n* Wrap actions with an authz helper (fail closed).\n* Keep `allowedOrigins` minimal and audited.\n\n---\n\n### NEXT-ACTION-002: Do not accidentally leak secrets through Server Action closure/binding patterns\n\nSeverity: Medium (High if important secrets are exposed)\n\nRequired:\n\n* MUST treat Server Action closed-over values as sensitive and design intentionally.\n* Next.js notes that closed-over values are encrypted/signed, but values passed through `.bind` are not encrypted; do not rely on `.bind` to protect secrets. ([Next.js][6])\n* If using a stable encryption key for Server Actions across deployments, MUST treat it as a secret and store securely (do not commit/log it). ([Next.js][6])\n\nInsecure patterns:\n\n* `myAction.bind(null, process.env.SECRET)` or binding sensitive tokens/IDs that should not be client-influenced.\n* Logging action arguments that include secrets.\n\nDetection hints:\n\n* Search for `.bind(` on Server Action functions.\n* Search for `process.env` usage near Server Actions.\n\nFix:\n\n* Avoid binding secrets into actions; fetch secrets server-side inside the action.\n* Keep action arguments minimal and validated.\n\n---\n\n### NEXT-CACHE-001: Prevent data leaks via static rendering and shared caching\n\nSeverity: High (Critical if cross-user data leak)\n\nRequired:\n\n* MUST ensure pages/endpoints that return user-specific or sensitive data are not statically generated or cached in a shared way.\n* Route Handlers are not cached by default, but GET handlers can opt into caching/static behavior; do not do this for per-user data. ([Next.js][1])\n* MUST treat `use cache` and similar caching mechanisms as potentially cross-user unless explicitly proven private; do not cache per-user DB results in shared caches. ([Next.js][1])\n* SHOULD set explicit `Cache-Control: no-store` / `private` for sensitive responses (auth/session/user data APIs).\n\nInsecure patterns:\n\n* `export const dynamic = 'force-static'` on a route that returns user-specific data. ([Next.js][1])\n* Using `use cache` around a function that queries user-specific data without a per-user cache key. ([Next.js][1])\n* Returning auth/session responses from GET endpoints with caching enabled.\n\nDetection hints:\n\n* Search for `dynamic = 'force-static'`, `revalidate`, `use cache`, `cacheLife`, `unstable_cache`.\n* Inspect all GET Route Handlers that are cached/static and confirm they only return public data.\n* Confirm that use of `cookies()`/`headers()` (dynamic APIs) is not accidentally removed in ways that make a route static. ([Next.js][1])\n\nFix:\n\n* Mark sensitive routes as dynamic and set `Cache-Control: no-store`.\n* Ensure caching keys include user identity if caching is truly needed (and store it in a user-private cache).\n\n---\n\n### NEXT-FILES-001: User uploads MUST be validated, stored safely, and served safely\n\nSeverity: Medium\n\nRequired:\n\n* MUST enforce upload size limits at the edge and in application logic.\n* MUST validate file type using allowlists and content checks (not only extension).\n* MUST store uploads outside the `public/` directory (anything under `public/` is served as static content by default).\n* MUST serve potentially active formats safely (`Content-Disposition: attachment`) unless explicitly intended.\n\nInsecure patterns:\n\n* Accepting arbitrary file types and serving them back inline.\n* Using user-supplied filename as the storage path.\n* Writing uploads into `public/uploads/` and serving them directly.\n\nDetection hints:\n\n* Search for `formData()` / multipart parsing, `fs.writeFile`, storage SDK usage.\n* Look for any write path under `public/`.\n* Look for “download” endpoints that set `Content-Type: text/html` or serve user files inline.\n\nFix:\n\n* Use a dedicated object store (S3/GCS) or a safe server-side directory outside static roots.\n* Generate random server-side filenames; store metadata separately.\n\n---\n\n### NEXT-PATH-001: Prevent path traversal and unsafe file access\n\nSeverity: High\n\nRequired:\n\n* MUST NOT use user-controlled strings as filesystem paths.\n* MUST validate and normalize identifiers; use allowlists and safe base directories.\n* MUST avoid reading arbitrary files based on request parameters.\n\nInsecure patterns:\n\n* `fs.readFile(request.nextUrl.searchParams.get('path'))`\n* `path.join(base, userPath)` without normalization + boundary checks\n\nDetection hints:\n\n* Search for `fs.` usage in Route Handlers/API Routes.\n* Search for `path.join`/`path.resolve` fed by request params.\n\nFix:\n\n* Use opaque IDs that map to server-side stored paths.\n* Enforce that resolved paths remain within an intended base directory.\n* Sanitize and disallow `..` from being used when creating urls\n\n---\n\n### NEXT-SSRF-001: Outbound requests using user-influenced URLs MUST be restricted\n\nSeverity: Medium (High in internal networks)\n\nNOTE: This is mostly only applicable to apps which will be deployed in a cloud/LAN setup or have other http services on the same box. Sometimes the feature requires this functionality unavoidably (webhooks).\n\nRequired:\n\n* MUST treat any server-side `fetch()` to a user-provided URL as high-risk.\n* SHOULD allowlist destinations (hosts/domains) for URL fetch features.\n* SHOULD block:\n\n  * localhost / private IP ranges / link-local\n  * cloud metadata endpoints\n* MUST restrict protocols to `http:` and `https:`.\n* SHOULD set strict timeouts and restrict redirects.\n\nInsecure patterns:\n\n* `await fetch(req.query.url)` or `await fetch((await request.json()).url)`\n* “URL preview” endpoints that fetch arbitrary URLs.\n\nDetection hints:\n\n* Search for `fetch(` in server code and trace where the URL comes from.\n* Look for “webhook tester”, “preview”, “import from URL” features.\n\nFix:\n\n* Parse URL, enforce `http/https`, allowlist hostnames, re-resolve DNS/IP to block private ranges.\n* Set timeouts (AbortSignal) and limit redirects.\n\n---\n\n### NEXT-REDIRECT-001: Prevent open redirects (including auth flows)\n\nSeverity: Low\n\nRequired:\n\n* MUST validate redirect targets derived from untrusted input (e.g., `next`, `redirect`, `returnTo`).\n* SHOULD prefer redirecting only to same-site relative paths.\n* MUST validate any absolute URL against an allowlist.\n* MUST ensure urls are `http` or `https:` schema, disallowing `javascript:` schema\n\nInsecure patterns:\n\n* `redirect(searchParams.get('next')!)`\n* `NextResponse.redirect(new URL(req.nextUrl.searchParams.get('to')!, req.url))` without checks\n\nDetection hints:\n\n* Search for `redirect(` (server components/actions) and `NextResponse.redirect`.\n* Search for `res.redirect(` in API Routes. ([Next.js][3])\n\nFix:\n\n* Only allow relative paths (`/path`) and reject protocol-relative (`//evil.com`) or absolute URLs.\n* If invalid, fall back to a safe default (home/dashboard).\n\n---\n\n### NEXT-CORS-001: CORS must be explicit and least-privilege\n\nSeverity: Medium (High if misconfigured with credentials)\n\nRequired:\n\n* If CORS is not needed, MUST keep it disabled.\n* Next.js API Routes do not set CORS headers by default, meaning they are same-origin by default; only enable CORS when you truly need it. ([Next.js][3])\n* If enabling CORS:\n\n  * MUST allowlist trusted origins (no reflection of arbitrary Origin)\n  * MUST be careful with credentialed requests (cookies); never combine broad origins with credentials.\n  * SHOULD restrict methods and headers.\n\nInsecure patterns:\n\n* `Access-Control-Allow-Origin: *` with `Access-Control-Allow-Credentials: true`\n* Reflecting `Origin` without validation.\n\nDetection hints:\n\n* Search for `Access-Control-Allow-Origin`, `cors`, “CORS” middleware/wrappers.\n* Review preflight `OPTIONS` handlers.\n\nFix:\n\n* Implement strict origin allowlist and minimal methods/headers.\n* Ensure cookies aren’t exposed cross-origin unless necessary and reviewed.\n\n---\n\n### NEXT-WEBHOOK-001: Webhook endpoints MUST verify authenticity using the raw body\n\nSeverity: Medium\n\nRequired:\n\n* MUST verify webhook signatures using the **raw request body** (not a re-serialized parsed object).\n* Next.js notes a use case for disabling body parsing is verifying the raw body of a webhook request. ([Next.js][3])\n\nInsecure patterns:\n\n* Verifying webhook signatures over `JSON.stringify(req.body)` (can change formatting).\n* Accepting webhooks with no signature verification and no allowlist.\n\nDetection hints:\n\n* Find webhook endpoints (`/api/webhook`, `/app/api/**/webhook`).\n* Check whether they use raw body verification.\n\nFix:\n\n* Disable Next.js automatic body parsing only for those webhook routes, read raw bytes safely, verify signature, then parse.\n\n---\n\n### NEXT-INJECT-001: Prevent SQL injection (use parameterized queries / ORM)\n\nSeverity: High\n\nRequired:\n\n* MUST use parameterized queries or an ORM that parameterizes under the hood.\n* MUST NOT build SQL by string concatenation / template strings with untrusted input.\n\nInsecure patterns:\n\n* ``db.query(`SELECT * FROM users WHERE id = ${id}`)``\n* `\"WHERE name = '\" + user + \"'\"`\n\nDetection hints:\n\n* Grep for `SELECT`, `INSERT`, `UPDATE`, `DELETE` strings.\n* Trace untrusted input (`params`, `searchParams`, `req.query`, `req.body`, `request.json()`) into DB calls.\n\nFix:\n\n* Use prepared statements / ORM query APIs.\n* Validate and coerce types before querying.\n\n---\n\n### NEXT-INJECT-002: Prevent OS command injection and unsafe subprocess use\n\nSeverity: Critical to High\n\nRequired:\n\n* MUST avoid executing OS commands with attacker-controlled input.\n* If subprocess is necessary:\n\n  * MUST pass args as an array (not a single shell string)\n  * MUST NOT use `shell: true` with attacker-influenced strings\n  * SHOULD use strict allowlists for any variable component\n\nInsecure patterns:\n\n* `exec(\"convert \" + filename)`\n* `spawn(\"bash\", [\"-c\", userInput])`\n* `spawn(userInput, [\"foo\"])`\n\nDetection hints:\n\n* Search for `child_process`, `exec`, `spawn`, `shell: true`.\n\nFix:\n\n* Use library APIs instead of shell commands.\n* Hard-code commands and allowlist validated parameters (and use `--` to separate flags where supported).\n\n---\n\n### NEXT-INJECT-003: Avoid dynamic code execution and unsafe deserialization\n\nSeverity: High to Critical\n\nRequired:\n\n* MUST NOT use `eval`, `new Function`, `vm.runIn*` on untrusted strings.\n* MUST treat deserializing complex formats (YAML, XML, custom serialization) as risky; use safe parsers and strict schemas.\n\nInsecure patterns:\n\n* `eval(req.body.code)`\n* Parsing YAML from user input with a non-safe schema.\n\nDetection hints:\n\n* Search for `eval(`, `new Function`, `vm.`, `require(` with non-literals.\n* Search for `js-yaml`, XML parsers, custom serializer usage on untrusted input.\n\nFix:\n\n* Remove dynamic execution; use safe interpreters or strict parsers.\n* Validate and constrain input.\n\n---\n\n### NEXT-LOG-001: Logging MUST NOT leak secrets or sensitive headers\n\nSeverity: Medium\n\nRequired:\n\n* MUST NOT log:\n\n  * `Authorization` headers\n  * cookies / session tokens\n  * request bodies containing credentials\n  * environment variables or configuration dumps\n* SHOULD implement structured logging with redaction.\n\nInsecure patterns:\n\n* `console.log(req.headers)` in auth endpoints\n* `console.log(process.env)` in server code\n\nDetection hints:\n\n* Search for `console.log(`, `logger.info(`, `debug(` in server routes/actions.\n* Check for logs of headers/cookies/body.\n\nFix:\n\n* Redact sensitive fields; log only what is needed for debugging.\n* Use safe error messages for clients; keep detail server-side only.\n\n---\n\n### NEXT-ERROR-001: Error handling MUST avoid leaking implementation details in production\n\nSeverity: Low\n\nRequired:\n\n* MUST not expose stack traces or internal error details to end users in production.\n* Ensure production mode behavior (Next.js production error handling differs from dev). ([Next.js][6])\n\nInsecure patterns:\n\n* Returning `err.stack` in JSON responses.\n* Showing detailed exception data to unauthenticated users.\n\nDetection hints:\n\n* Search for `res.status(500).json(err)` or `return Response.json(err)`.\n* Verify error responses are sanitized.\n\nFix:\n\n* Return generic error messages to clients; log details server-side with redaction.\n\n---\n\n### NEXT-PROXY-001: Proxy/Middleware must not introduce header smuggling or unsafe header forwarding\n\nSeverity: Medium\n\nRequired:\n\n* MUST be careful when copying/forwarding request headers upstream:\n\n  * Do not forward attacker-controlled `x-forwarded-*` headers unless you have a trusted proxy chain.\n  * Do not forward `Authorization`/cookies to unrelated outbound services.\n* Next.js Proxy patterns often mutate headers; ensure this doesn’t create security issues.\n\nInsecure patterns:\n\n* Blindly cloning all request headers to an outbound `fetch()` call.\n* Trusting `x-forwarded-host` or `host` to construct sensitive absolute URLs without allowlisting.\n\nDetection hints:\n\n* Search `headers()` and `request.headers` usage (especially for URL building). ([Next.js][4])\n* Search Proxy/Middleware for header rewrites.\n\nFix:\n\n* Allowlist forwarded headers explicitly.\n* Validate hostnames before using them to build callback URLs or redirects.\n\n---\n\n### NEXT-HOST-001: Host/Origin-derived URL construction MUST be allowlisted\n\nSeverity: Medium\n\nRequired:\n\n* MUST NOT generate security-sensitive absolute URLs (password reset links, OAuth callback URLs, email verification links) directly from unvalidated `Host` headers.\n* For Server Actions, Origin/Host matching is part of CSRF mitigation; do not weaken it. ([Next.js][5])\n\nInsecure patterns:\n\n* `const base = \"https://\" + request.headers.get(\"host\")`\n* Using unvalidated `x-forwarded-host` for absolute URL generation.\n\nDetection hints:\n\n* Grep for `.get('host')`, `.get('x-forwarded-host')`, and absolute URL building.\n* Review auth-related email link generation code.\n\nFix:\n\n* Use a configured, allowlisted canonical app origin (e.g., `APP_ORIGIN=https://example.com`).\n* Allowlist hostnames; fail closed.\n\n---\n\n### NEXT-DOS-001: Rate limiting and resource controls MUST exist for abuse-prone endpoints\n\nSeverity: Medium\n\nRequired:\n\n* SHOULD implement rate limiting/throttling for:\n\n  * login, password reset, signup\n  * expensive Server Actions\n  * webhook ingestion\n* MUST implement request size limits (see NEXT-LIMITS-001).\n* If self-hosting, MUST rely on reverse proxy for additional protections. ([Next.js][8])\n\nInsecure patterns:\n\n* No throttling on login/reset endpoints.\n* Expensive actions callable without auth or with unlimited frequency.\n\nDetection hints:\n\n* Identify auth endpoints and check for rate limiting.\n* Search for “send email”, “charge”, “generate report” flows.\n\nFix:\n\n* Add edge rate limiting and app-level user/IP throttles.\n* Add job queues for heavy work; return 202 when appropriate.\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* Production misconfig:\n\n  * `next dev`, `NODE_ENV=development`, dev-only start commands ([Next.js][7])\n* Secrets exposure:\n\n  * `.env` committed, `NEXT_PUBLIC_` on sensitive variables ([Next.js][7])\n  * `process.env` used in `\"use client\"` modules\n* Auth coverage:\n\n  * `app/**/route.ts` or `pages/api/**` with no auth checks ([Next.js][1])\n  * `\"use server\"` actions with DB writes and no authz ([Next.js][6])\n  * `proxy.ts` / `middleware.ts` matchers that exclude sensitive routes ([Next.js][12])\n* CSRF:\n\n  * cookie-auth POST/PUT/PATCH/DELETE with no token/origin checks\n  * `serverActions.allowedOrigins` too broad ([Next.js][5])\n* XSS:\n\n  * `dangerouslySetInnerHTML`, raw HTML markdown rendering\n  * missing CSP / overly permissive CSP ([Next.js][7])\n* Caching/data leak:\n\n  * `dynamic = 'force-static'` on sensitive GET handlers ([Next.js][1])\n  * `use cache`, `cacheLife`, `unstable_cache` around user-specific data ([Next.js][1])\n* Files:\n\n  * writing uploads under `public/`\n  * `fs.readFile` / `path.join` with request input\n* SSRF:\n\n  * `fetch(userProvidedUrl)` from Route Handlers / Server Actions\n* Redirect:\n\n  * `redirect(searchParams.get('next'))`, `NextResponse.redirect(...)`, `res.redirect(req.query.next)` ([Next.js][3])\n* CORS:\n\n  * wildcard origins, origin reflection, credentials + broad origins ([Next.js][3])\n* Limits:\n\n  * API routes with `bodyParser: false` and no raw-body verification for webhooks ([Next.js][3])\n  * `serverActions.bodySizeLimit` raised without justification ([Next.js][5])\n* Dependency hygiene:\n\n  * old `next` versions that conflict with support policy/advisories ([Next.js][10])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (HTML/DOM, SQL, subprocess, files, redirect, outbound HTTP)\n* protective controls present (schema validation, allowlists, middleware/proxy checks, authz helpers, edge protections)\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary framework documentation (Next.js):\n\n* Next.js Docs: Installation (system requirements / Node version) — `https://nextjs.org/docs/app/getting-started/installation`\n* Next.js Docs: Route Handlers — `https://nextjs.org/docs/app/getting-started/route-handlers`\n* Next.js Docs: API Routes (Pages Router) — `https://nextjs.org/docs/pages/building-your-application/routing/api-routes`\n* Next.js Docs: Environment Variables — `https://nextjs.org/docs/pages/guides/environment-variables`\n* Next.js Docs: Data Security — `https://nextjs.org/docs/app/guides/data-security`\n* Next.js Docs: Content Security Policy — `https://nextjs.org/docs/app/guides/content-security-policy`\n* Next.js Docs: Proxy — `https://nextjs.org/docs/app/getting-started/proxy`\n* Next.js Docs: `serverActions.allowedOrigins` and `serverActions.bodySizeLimit` — `https://nextjs.org/docs/app/api-reference/config/next-config-js/serverActions`\n* Next.js Docs: `cookies()` — `https://nextjs.org/docs/app/api-reference/functions/cookies`\n* Next.js Docs: `headers()` — `https://nextjs.org/docs/app/api-reference/functions/headers`\n* Next.js Docs: Self-hosting (reverse proxy guidance) — `https://nextjs.org/docs/pages/guides/self-hosting`\n* Next.js Docs: Support policy (supported versions/LTS) — `https://nextjs.org/docs/support-policy`\n\nNext.js security guidance & advisories:\n\n* Next.js Blog: How to think about security in Next.js — `https://nextjs.org/blog/security-nextjs-server-components-actions`\n* GitHub Security Advisory: Next.js DoS via Server Components / Server Actions (CVE-2026-23864) — `https://github.com/advisories/GHSA-fq29-rrrv-cq2m`\n* Next.js Blog: Security update (example security advisory context) — `https://nextjs.org/blog/security-update`\n\nGeneral web security references (recommended baseline):\n\n* OWASP Cheat Sheet Series (CSRF, Session Management, XSS Prevention, SSRF Prevention, File Upload, HTTP Headers) — `https://cheatsheetseries.owasp.org/`\n\n[1]: https://nextjs.org/docs/app/getting-started/route-handlers \"Getting Started: Route Handlers | Next.js\"\n[2]: https://nextjs.org/docs/app/getting-started/deploying?utm_source=chatgpt.com \"Getting Started: Deploying\"\n[3]: https://nextjs.org/docs/pages/building-your-application/routing/api-routes \"Routing: API Routes | Next.js\"\n[4]: https://nextjs.org/docs/app/api-reference/functions/headers \"Functions: headers | Next.js\"\n[5]: https://nextjs.org/docs/app/api-reference/config/next-config-js/serverActions \"next.config.js: serverActions | Next.js\"\n[6]: https://nextjs.org/blog/security-nextjs-server-components-actions \"How to Think About Security in Next.js | Next.js\"\n[7]: https://nextjs.org/docs/pages/guides/environment-variables \"Guides: Environment Variables | Next.js\"\n[8]: https://nextjs.org/docs/pages/guides/self-hosting?utm_source=chatgpt.com \"Guides: Self-Hosting\"\n[9]: https://nextjs.org/docs/app/api-reference/functions/cookies \"Functions: cookies | Next.js\"\n[10]: https://nextjs.org/blog/next-16?utm_source=chatgpt.com \"Next.js 16\"\n[11]: https://github.com/vercel/next.js/security/advisories/GHSA-9g9p-9gw9-jx7f?utm_source=chatgpt.com \"Denial of Service in Image Optimizer · Advisory\"\n[12]: https://nextjs.org/docs/pages/guides/authentication \"Guides: Authentication | Next.js\"\n","isInternal":false,"tokens":9783,"sizeBytes":43423},{"name":"javascript-typescript-react-web-frontend-security.md","path":"core/skills/builtin/security-best-practices/references/javascript-typescript-react-web-frontend-security.md","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/security-best-practices/references/javascript-typescript-react-web-frontend-security.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# React (JavaScript/TypeScript) Web Security Spec (React 19.x, TypeScript 5.x)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new React code.\n2. **Security review / vulnerability hunting** in existing React code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, OAuth client secrets, private keys, session cookies, JWTs, signing keys).\n\n  * Frontend note: anything shipped to the browser is observable by end users and attackers (view-source, devtools, proxies); never treat client code or “env vars in the bundle” as secret. ([create-react-app.dev][1])\n* MUST NOT “fix” security by disabling protections (e.g., turning off CSP to “make it work”, adding `unsafe-inline`/`unsafe-eval` without a documented, constrained plan, disabling CSRF protections when using cookies, widening CORS, skipping sanitization, or “temporary” bypasses that ship). ([OWASP Cheat Sheet Series][2])\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and configuration values that justify the claim.\n* MUST treat uncertainty honestly: if a protection might exist in infra (CDN/WAF/reverse proxy), report it as “not visible in app code; verify via runtime headers / edge config”.\n* MUST assume any data that crosses a trust boundary (URL, storage, network, postMessage, third-party scripts) can be attacker-influenced unless proven otherwise (see §2.1).\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new React code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default APIs and proven libraries over custom security code.\n* MUST avoid introducing new risky sinks (raw HTML insertion, direct DOM sinks like `innerHTML`, dynamic code execution, untrusted redirects/navigation, third‑party script injection, unsafe token storage, etc.). ([MDN Web Docs][3])\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a React repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. App entrypoints, build tooling (Vite/Webpack/CRA/Next), deployment configs, CDN/static hosting config.\n2. Secrets & configuration exposure (env vars, runtime config injection, source maps).\n3. Rendering of untrusted data (XSS/DOM XSS), especially `dangerouslySetInnerHTML`, markdown/HTML renderers, URL attributes.\n4. Direct DOM usage and dangerous JS execution (`innerHTML`, `eval`, `new Function`, `document.write`, etc.).\n5. Auth & session patterns (token storage, cookies, CSRF interactions, OAuth flows).\n6. Network layer (axios/fetch wrappers, dynamic base URLs, credentialed requests, data exfil risks).\n7. Navigation & redirect handling (open redirects, `window.location`, `target=_blank`, `window.open`).\n8. Third-party scripts/tags/analytics and integrity controls (CSP, SRI).\n9. Service worker/PWA behavior (HTTPS, caching rules, update strategy).\n10. Security headers posture (CSP, clickjacking, nosniff, referrer policy) in app or at the edge. ([OWASP Cheat Sheet Series][2])\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nExamples include:\n\n* URL-derived data: `window.location`, query params, hash fragments, route params.\n* Any data from browser storage: `localStorage`, `sessionStorage`, `IndexedDB` (including data previously written by the app—because XSS or extensions can tamper with it). ([OWASP Cheat Sheet Series][4])\n* Any data from cross-window messaging: `window.postMessage` payloads. ([OWASP Cheat Sheet Series][4])\n* Any data from remote APIs, webhooks proxied to the client, GraphQL responses, CMS content, feature flag services.\n* Any persisted user content (profiles, comments, rich text, markdown) rendered in the UI.\n* Any data produced by third-party scripts or tag managers (treat as untrusted unless strongly controlled). ([OWASP Cheat Sheet Series][5])\n\n### 2.2 State-changing request (frontend perspective)\n\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook), or initiate privileged actions.\n\nFrontend-specific note:\n\n* State changes are often triggered by `fetch/axios` calls or form submissions. If authentication is cookie-based, these calls can be CSRF-relevant (§4 REACT-CSRF-001). ([OWASP Cheat Sheet Series][6])\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + component/function + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common React frontend misconfigurations.\n\n### 3.1 Production build and configuration hygiene (MUST)\n\n* MUST ship a production build (minified, no dev-only overlays/tools, correct mode flags).\n* MUST ensure build-time configuration does not embed secrets into the shipped JS/HTML/CSS. Build-time “environment variables” are not secret; treat them as public. ([create-react-app.dev][1])\n* SHOULD treat source maps as sensitive operational artifacts:\n\n  * Either don’t publish them publicly, or publish them only where intended (e.g., behind auth or to an error-reporting provider), because they can reveal code structure and internal URLs.\n\n### 3.2 Browser-enforced protections (SHOULD, but baseline expectation for modern apps)\n\n* SHOULD deploy a CSP as defense-in-depth against XSS, and keep it compatible with your React build (avoid `unsafe-inline` and `unsafe-eval` unless strictly necessary and documented). ([OWASP Cheat Sheet Series][2])\n* SHOULD use Subresource Integrity (SRI) for any third-party script/style loaded from a CDN (or self-host instead). ([MDN Web Docs][7])\n* SHOULD enable clickjacking defenses via `frame-ancestors` (CSP) and/or `X-Frame-Options`, unless embedding is an explicit product requirement. ([MDN Web Docs][8])\n\n### 3.3 High-risk features baseline (MUST if used)\n\n* If rendering any user-provided HTML/markdown/rich text:\n\n  * MUST sanitize before insertion and avoid raw DOM sinks. ([OWASP Cheat Sheet Series][9])\n* If using service workers / PWA:\n\n  * MUST serve over HTTPS and implement a safe caching/update strategy (service workers are powerful request/response proxies). ([MDN Web Docs][10])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### REACT-CONFIG-001: Never embed secrets in the client bundle (env vars are public)\n\nSeverity: Critical (if secrets exposed)\n\nRequired:\n\n* MUST NOT place secrets in React code, in `public/` assets, or in build-time environment variables intended for client consumption.\n* MUST assume any value available to the React app at runtime can be extracted by an attacker.\n\nInsecure patterns:\n\n* Using build-time env vars for secrets:\n\n  * `process.env.REACT_APP_*` containing private keys or credentials.\n  * `import.meta.env.VITE_*` containing secrets.\n* Hard-coded secrets in JS/TS, `.env` committed, or secrets in `public/config.json` served to all users.\n\nDetection hints:\n\n* Search for:\n\n  * `REACT_APP_`, `VITE_`, `NEXT_PUBLIC_`, `process.env.`, `import.meta.env.`\n  * `apiKey`, `secret`, `token`, `private`, `password`, `client_secret`\n* Inspect `public/` for runtime config JSON.\n\nFix:\n\n* Move secrets server-side (API, BFF, serverless function).\n* Use a backend to mint short-lived, scoped tokens if the browser needs to call third-party APIs.\n\nNotes:\n\n* CRA explicitly warns not to store secrets and notes env vars are embedded into the build and visible to anyone inspecting files. ([create-react-app.dev][1])\n* Vite explicitly notes that variables exposed to client code end up in the client bundle and should not contain sensitive info. ([vitejs][11])\n\n---\n\n### REACT-XSS-001: Do not use `dangerouslySetInnerHTML` with untrusted content (sanitize or avoid)\n\nSeverity: High (Only if you can prove attacker-controlled HTML reaches it)\n\nRequired:\n\n* MUST avoid `dangerouslySetInnerHTML` unless absolutely necessary.\n* If it must be used:\n\n  * MUST sanitize untrusted HTML with a proven sanitizer (e.g., DOMPurify) and an allowlist-oriented configuration.\n  * MUST keep the sanitization logic centralized and heavily reviewed.\n  * SHOULD add a CSP and consider Trusted Types (see REACT-TT-001).\n\nInsecure patterns:\n\n* `<div dangerouslySetInnerHTML={{ __html: userHtml }} />` where `userHtml` is from API/URL/storage.\n* “Sanitization” done with regexes, ad-hoc stripping, or incomplete allowlists.\n\nDetection hints:\n\n* Grep: `dangerouslySetInnerHTML`, `__html:`\n* Trace the origin of the HTML string (API/CMS/URL/localStorage).\n\nFix:\n\n* Replace with safe rendering:\n\n  * Render structured data as React elements/components instead of HTML strings.\n  * If rich text is required, sanitize with DOMPurify (or equivalent) and render the sanitized output.\n* Add CSP; remove dangerous sinks where possible.\n\nNotes:\n\n* React explicitly warns that `dangerouslySetInnerHTML` is dangerous and can introduce XSS if misused. ([React][12])\n* OWASP explicitly calls out React’s `dangerouslySetInnerHTML` without sanitization as a common framework “escape hatch” pitfall. ([OWASP Cheat Sheet Series][9])\n* DOMPurify describes itself as an XSS sanitizer for HTML/SVG/MathML. ([GitHub][13])\n\n---\n\n### REACT-XSS-002: Rely on React’s escaping-by-default behavior; do not bypass it\n\nSeverity: High (when bypassed)\n\nRequired:\n\n* MUST render untrusted strings via normal JSX interpolation (`{value}`) and React props, which are escaped by default.\n* MUST NOT build HTML strings from untrusted data and then inject them into the DOM via any means.\n* SHOULD treat any “escape hatch” as high risk and require review.\n\nInsecure patterns:\n\n* Converting untrusted text into HTML and injecting it:\n\n  * `element.innerHTML = userValue`\n  * `document.write(userValue)`\n  * `insertAdjacentHTML(..., userValue)`\n\nDetection hints:\n\n* Grep for DOM sinks: `innerHTML`, `outerHTML`, `insertAdjacentHTML`, `document.write`, `DOMParser`, `createContextualFragment`.\n\nFix:\n\n* Render text content through React (JSX) so it is escaped.\n* If you truly need HTML, sanitize and apply REACT-XSS-001 + REACT-TT-001.\n\nNotes:\n\n* React documentation (JSX) states that React DOM escapes values embedded in JSX before rendering to help prevent injection attacks. ([React][14])\n\n---\n\n### REACT-DOM-001: Avoid DOM XSS injection sinks in React code (use safe alternatives)\n\nSeverity: High\n\nRequired:\n\n* MUST avoid direct DOM injection sinks, even outside React rendering, unless strongly controlled.\n* If a DOM sink is required:\n\n  * MUST ensure inputs are trusted/validated/sanitized.\n  * SHOULD enforce Trusted Types (REACT-TT-001).\n\nInsecure patterns:\n\n* `someEl.innerHTML = untrusted`\n* `document.write(untrusted)`\n* `new DOMParser().parseFromString(untrusted, 'text/html')` followed by insertion\n\nDetection hints:\n\n* Grep for: `innerHTML`, `outerHTML`, `document.write`, `DOMParser`, `Range().createContextualFragment`, `insertAdjacentHTML`\n\nFix:\n\n* Prefer:\n\n  * `textContent` for text insertion.\n  * React rendering rather than manual DOM manipulation.\n  * A vetted sanitizer for any required HTML parsing.\n\nNotes:\n\n* Trusted Types documentation defines HTML sinks like `Element.innerHTML` and `document.write()` as injection sinks that can execute script when given attacker-controlled input. ([MDN Web Docs][3])\n* OWASP HTML5 guidance recommends using `textContent` instead of `innerHTML` for assigning untrusted data. ([OWASP Cheat Sheet Series][4])\n\n---\n\n### REACT-URL-001: Validate and constrain untrusted URLs used in `href`, `src`, navigation, and redirects\n\nSeverity: High Only when you can prove they are attacker controlled\n\nRequired:\n\n* MUST treat any URL derived from untrusted input as dangerous.\n* MUST allowlist schemes and (when applicable) hosts:\n\n  * Typically allow only `https:` (and maybe `http:` for localhost/dev) and relative URLs for in-app navigation.\n  * MUST explicitly block `javascript:` and dangerous `data:` uses unless you have specialized validation and a clear use case.\n* SHOULD prefer same-site relative paths (e.g., `/settings`) over absolute URLs.\n* MUST validate “returnTo/next/redirect” parameters (see REACT-REDIRECT-001).\n\nInsecure patterns:\n\n* `<img src={userProvidedUrl}>...` (can be used for tracking / data exfil; also risky if used for scripts/iframes)\n* `window.location = next`\n* `navigate(next)` where `next` comes from query params without validation\n\nDetection hints:\n\n* Search for:\n\n  * `href={`, `src={`, `window.location`, `location.href`, `window.open`, `navigate(`, `redirectTo`, `returnTo`, `next=`\n* Track whether the value is derived from URL/query/storage/API.\n\nFix:\n\n* Implement a shared `safeUrl()` utility:\n\n  * Parse with `new URL(value, base)`\n  * Enforce scheme allowlist and host allowlist (or enforce same-origin)\n  * For redirects: allow only relative paths (starting with `/`) or a strict allowlist of absolute origins.\n* Fall back to a safe default when validation fails.\n\nNotes:\n\n* OWASP explicitly notes React’s `dangerouslySetInnerHTML` risk and also states React cannot safely handle `javascript:` or `data:` URLs without specialized validation. ([OWASP Cheat Sheet Series][9])\n\n---\n\n### REACT-MARKUP-001: Markdown / rich text rendering must be configured safely\n\nSeverity: Medium\n\nRequired:\n\n* MUST assume markdown/rich text can be attacker-controlled if it comes from users or CMS.\n* MUST ensure raw HTML is not rendered unless sanitized.\n* SHOULD prefer markdown renderers that:\n\n  * Do not allow raw HTML by default, or\n  * Can be configured to disallow raw HTML, or\n  * Sanitize HTML output before rendering.\n\nInsecure patterns:\n\n* Markdown rendering with “raw HTML passthrough” enabled (e.g., options/plugins that allow HTML).\n* Rendering user-provided SVG/MathML/HTML inline without sanitization.\n\nDetection hints:\n\n* Search for common libraries and risky options:\n\n  * `marked`, `markdown-it`, `react-markdown`, `rehype-raw`, `sanitize: false`, `allowDangerousHtml`, etc.\n* Look for `dangerouslySetInnerHTML` used with “markdown output”.\n\nFix:\n\n* Disable raw HTML passthrough.\n* Sanitize output with a proven sanitizer (e.g., DOMPurify) before rendering.\n\nNotes:\n\n* OWASP XSS guidance emphasizes that framework escape hatches require output encoding and/or HTML sanitization. ([OWASP Cheat Sheet Series][9])\n\n---\n\n### REACT-TT-001: Use Trusted Types (with CSP) to harden DOM XSS sinks where feasible\n\nSeverity: Low\n\nRequired:\n\n* SHOULD consider enabling Trusted Types in report-only mode first, then enforce once violations are addressed.\n* SHOULD centralize Trusted Types policies and treat them as high-risk code requiring review.\n* MUST NOT create permissive policies that simply “pass through” untrusted strings.\n\nInsecure patterns:\n\n* A Trusted Types policy that returns the raw string without sanitization for HTML sinks.\n* Many scattered policies across the codebase (hard to audit).\n\nDetection hints:\n\n* Search for:\n\n  * `trustedTypes.createPolicy`\n  * CSP directives: `require-trusted-types-for`, `trusted-types`\n* Search for remaining DOM sinks (REACT-DOM-001).\n\nFix:\n\n* Implement a small number of tightly scoped policies:\n\n  * HTML policy uses sanitizer (DOMPurify or equivalent).\n  * Script URL policy uses strict allowlists.\n* Run in report-only mode, fix violations, then enforce.\n\nNotes:\n\n* MDN describes Trusted Types as a way to ensure input is transformed (commonly sanitized) before being passed to injection sinks, and highlights HTML sinks (`innerHTML`, `document.write`) and JS URL sinks (`script.src`). ([MDN Web Docs][3])\n* The W3C Trusted Types spec frames this as reducing DOM XSS risk by locking down sinks to typed values created by reviewed policies. ([W3C][15])\n\n---\n\n### REACT-CSP-001: Deploy and maintain a CSP as defense-in-depth (especially when rendering untrusted content)\n\nSeverity: Medium to High\n\nRequired:\n\n* SHOULD deploy CSP in production; MUST do so for apps that render untrusted content or integrate third-party scripts.\n* SHOULD avoid `unsafe-inline` and `unsafe-eval` when possible.\n* SHOULD use CSP nonces/hashes for inline scripts if needed, and keep policy realistic.\n* SHOULD use CSP to require/encourage SRI where appropriate.\n\nInsecure patterns:\n\n* No CSP at all on the app shell (SPA entry HTML).\n* CSP that relies on `unsafe-inline`/`unsafe-eval` broadly without justification.\n* `script-src *` or overly broad sources.\n\nDetection hints:\n\n* Look for CSP configuration:\n\n  * Server/CDN config, headers in `index.html` responses, or framework config.\n* If absent in repo, mark as “verify at edge”.\n\nFix:\n\n* Add CSP via HTTP response headers (preferred).\n* Start with report-only to reduce breakage, then enforce.\n\nNotes:\n\n* OWASP describes CSP as “defense in depth” against XSS and notes it can help enforce SRI even on static sites, but should not be the only defense. ([OWASP Cheat Sheet Series][2])\n\n---\n\n### REACT-SRI-001: Use Subresource Integrity (SRI) for third-party scripts and styles (or self-host)\n\nSeverity: Low\n\nRequired:\n\n* MUST treat third-party JS as equivalent to running arbitrary code in your origin.\n* If loading from a CDN or third party:\n\n  * SHOULD use SRI (`integrity=...`) and `crossorigin` where applicable.\n  * SHOULD pin exact versions (avoid “latest” URLs).\n  * SHOULD prefer self-hosting for critical code.\n\nInsecure patterns:\n\n* `<script src=\"https://cdn.example.com/lib/latest.js\"></script>` with no integrity.\n* Tag managers that dynamically load arbitrary scripts without governance.\n\nDetection hints:\n\n* Search in `public/index.html`, templates, or SSR wrappers for:\n\n  * `<script src=`, `<link rel=\"stylesheet\" href=`\n  * Tag manager snippets (GTM, Segment, etc.)\n* Identify scripts loaded dynamically in runtime JS.\n\nFix:\n\n* Add SRI hashes for stable third-party assets or self-host.\n* Apply governance controls for tag managers (see REACT-3P-001).\n\nNotes:\n\n* MDN describes SRI as a security feature enabling browsers to verify fetched resources (e.g., from a CDN) haven’t been manipulated by checking a cryptographic hash. ([MDN Web Docs][7])\n* OWASP CSP guidance notes CSP can enforce SRI and is useful even on static sites. ([OWASP Cheat Sheet Series][2])\n\n---\n\n### REACT-3P-001: Third-party JavaScript and tag managers must be minimized and governed\n\nSeverity: High\n\nRequired:\n\n* MUST minimize third-party scripts and treat each as a supply-chain risk.\n* MUST know exactly what third-party JS executes in your origin and why.\n* SHOULD implement governance:\n\n  * Review and pin versions (or mirror in-house).\n  * Restrict data access (data-layer approach).\n  * Use SRI and CSP; consider sandboxing untrusted UI in iframes where possible.\n\nInsecure patterns:\n\n* Unreviewed analytics/ads scripts running with full access to DOM, cookies, storage, and user data.\n* Tag managers that can be changed by non-engineering roles with no change control.\n\nDetection hints:\n\n* Search for common vendor snippets in HTML/JS:\n\n  * GTM, Segment, Hotjar, FullStory, etc.\n* Look for dynamic script insertion:\n\n  * `document.createElement('script')`, `.src = ...`, `.appendChild(script)`\n\nFix:\n\n* Reduce to only necessary vendors.\n* Where feasible:\n\n  * Self-host or mirror scripts.\n  * Use SRI.\n  * Limit data exposure via a controlled data layer.\n\nNotes:\n\n* OWASP notes third-party JS server compromise can inject malicious JS, and highlights risks like arbitrary code execution and disclosure of sensitive info to third parties. ([OWASP Cheat Sheet Series][5])\n\n---\n\n### REACT-AUTH-001: Token and session handling must be resilient to XSS (avoid sensitive storage in Web Storage)\n\nSeverity: Medium\n\nRequired:\n\n* SHOULD avoid storing session identifiers or long-lived tokens in `localStorage` (and generally in Web Storage) because XSS can exfiltrate them.\n* If tokens must exist client-side:\n\n  * SHOULD prefer in-memory storage with short lifetimes and refresh mechanisms.\n  * MUST scope and rotate tokens; avoid long-lived bearer tokens in persistent storage.\n* SHOULD prefer HTTPOnly cookies for session tokens when possible (requires CSRF strategy: see REACT-CSRF-001).\n\nInsecure patterns:\n\n* `localStorage.setItem('token', ...)` / `sessionStorage.setItem('token', ...)` for auth tokens.\n* Persisting refresh tokens in `localStorage`.\n* Treating data from Web Storage as trusted.\n\nDetection hints:\n\n* Grep for: `localStorage.`, `sessionStorage.`, `setItem(`, `getItem(`, `token`, `jwt`, `refresh`\n* Search auth code for “remember me” storing tokens persistently.\n\nFix:\n\n* Move to HTTPOnly cookies (server change) + CSRF protections, or use short-lived in-memory tokens.\n* Reduce token scope and lifetime.\n\nNotes:\n\n* OWASP HTML5 guidance recommends avoiding sensitive info and session identifiers in local storage and warns that a single XSS can steal all data in Web Storage. ([OWASP Cheat Sheet Series][4])\n* OAuth browser-based apps guidance discusses that tokens stored in persistent browser storage like localStorage can be accessible to malicious JS (e.g., via XSS). ([IETF Datatracker][16])\n\n---\n\n### REACT-CSRF-001: Cookie-authenticated, state-changing requests MUST be CSRF-protected\n\nSeverity: High\n\nNOTE: If the application does not use cookie based auth (using Authentication header for example), then CSRF is not a concern.\n\nRequired:\n\n* If the app relies on cookies for authentication:\n\n  * MUST protect state-changing requests (POST/PUT/PATCH/DELETE) against CSRF.\n  * SHOULD include a CSRF token mechanism (synchronizer token or double-submit cookie) or other robust pattern appropriate to the backend.\n  * SHOULD use SameSite cookies as defense-in-depth, not as the sole defense.\n\nInsecure patterns:\n\n* `fetch('/api/transfer', { method: 'POST', credentials: 'include' })` with no CSRF token/header, relying only on cookies.\n* Using GET for state-changing operations.\n\nDetection hints:\n\n* Enumerate state-changing network calls and check:\n\n  * Is `credentials: 'include'` or `withCredentials: true` used?\n  * Is a CSRF token header included (e.g., `X-CSRF-Token`)?\n* Search for “csrf” utilities; if absent, treat as suspicious.\n\nFix:\n\n* Add CSRF token flow:\n\n  * Fetch token from a safe endpoint and attach to state-changing requests.\n  * Validate server-side.\n* Keep SameSite cookies and Origin/Referer validation as defense-in-depth.\n\nNotes:\n\n* OWASP CSRF guidance explains SameSite behavior (Lax/Strict/None) as a defense-in-depth technique and why Lax is often the usability/security balance, but it is not a complete substitute for CSRF protections. ([OWASP Cheat Sheet Series][6])\n\n---\n\n### REACT-AUTHZ-001: Do not rely on frontend-only authorization\n\nSeverity: High (only if used as primary protection)\n\nRequired:\n\n* MUST treat all frontend authorization checks as UX only.\n* MUST enforce authorization on the server for any protected resource or action.\n\nInsecure patterns:\n\n* “Protected” actions hidden in UI but callable by API without server checks.\n* Client checks like `if (user.isAdmin) { showAdminPanel(); }` with no server-side enforcement.\n\nDetection hints:\n\n* Look for UI gating around sensitive actions and verify server endpoints enforce authorization.\n* In a frontend-only audit, report as “client checks are not security; verify backend”.\n\nFix:\n\n* Add/confirm server-side authorization checks.\n* Keep frontend gating only as convenience.\n\nNotes:\n\n* This is a general web app security property; React cannot protect server resources by itself.\n\n---\n\n### REACT-NET-001: Prevent data exfiltration and credential leakage via dynamic outbound requests\n\nSeverity: Medium to High\n\nRequired:\n\n* MUST avoid making authenticated requests to attacker-controlled origins.\n* SHOULD avoid allowing user input to control request destination (scheme/host/port).\n* SHOULD centralize network clients (fetch/axios) with:\n\n  * fixed `baseURL` (or strict allowlist),\n  * strict handling of redirects,\n  * explicit `credentials` usage.\n\nInsecure patterns:\n\n* `fetch(userProvidedUrl, { credentials: 'include' })`\n* `axios.create({ baseURL: userProvidedBase })`\n* “URL fetch/preview” features in the client that hit arbitrary domains with sensitive headers.\n\nDetection hints:\n\n* Search for `fetch(` / `axios(` where the first argument or `baseURL` is derived from:\n\n  * query params, localStorage, API responses, postMessage\n* Search for `credentials: 'include'`, `withCredentials: true`.\n\nFix:\n\n* Enforce destination allowlists; disallow cross-origin requests unless explicitly required.\n* Strip credentials/Authorization headers for any non-allowlisted destination.\n\nNotes:\n\n* Even if the browser limits some cross-origin behavior, leaking tokens/headers to untrusted endpoints is still a common failure mode.\n\n---\n\n### REACT-REDIRECT-001: Prevent open redirects and untrusted navigation\n\nSeverity: Medium\n\nRequired:\n\n* MUST validate redirect/navigation targets derived from untrusted input (`next`, `returnTo`, `redirect`).\n* SHOULD only allow same-site relative paths, or a strict allowlist of trusted origins for absolute URLs.\n\nInsecure patterns:\n\n* `window.location.href = new URLSearchParams(location.search).get('next')`\n* `navigate(next)` where `next` comes from query params.\n\nDetection hints:\n\n* Search for: `next`, `returnTo`, `redirect`, `window.location`, `navigate(`\n* Trace origin of the redirect target.\n\nFix:\n\n* Only allow relative paths (`/^\\/[^\\s]*$/`) or allowlisted origins.\n* Fall back to a safe default (e.g., `/`) when invalid.\n\nNotes:\n\n* Open redirects are frequently used in phishing and can undermine SSO/OAuth flows.\n\n---\n\n### REACT-SW-001: Service workers are high-privilege; require HTTPS and safe caching/update rules\n\nSeverity: Medium\n\nRequired:\n\n* MUST serve service workers over HTTPS (except `localhost` dev), and deploy only in secure contexts.\n* MUST avoid caching sensitive authenticated API responses unless explicitly designed and threat-modeled.\n* SHOULD implement safe update strategy (prompt reload, versioned caches, remove old caches on activate).\n\nInsecure patterns:\n\n* Registering a service worker for an authenticated app and caching “everything” indiscriminately.\n* Long-lived caches containing PII or user-specific content shared across accounts.\n\nDetection hints:\n\n* Search for:\n\n  * `navigator.serviceWorker.register`\n  * `workbox`, `precacheAndRoute`, custom `fetch` handlers\n* Inspect caching patterns (`caches.open`, `cache.put`, `respondWith`).\n\nFix:\n\n* Restrict caching to static assets only (JS/CSS/images) unless you have a designed offline model.\n* Ensure cache keys are user-scoped if user-specific data must be cached.\n* Provide a clear update mechanism.\n\nNotes:\n\n* MDN notes service workers require HTTPS for security reasons and act like a proxy for requests/responses. ([MDN Web Docs][10])\n* “Secure contexts” exist to prevent MITM attackers from accessing powerful APIs; service workers are an example of such a powerful feature. ([MDN Web Docs][18])\n\n---\n\n### REACT-HEADERS-001: Ensure essential security headers are set for the React app shell (app or edge)\n\nSeverity: Medium\n\nRequired (typical SPA served from an origin):\n\n* SHOULD set:\n\n  * CSP (`Content-Security-Policy`)\n  * `X-Content-Type-Options: nosniff`\n  * Clickjacking protection (`frame-ancestors` in CSP and/or `X-Frame-Options`)\n  * `Referrer-Policy`\n  * `Permissions-Policy` as appropriate\n* MUST ensure these are set somewhere (CDN/edge/server), even if not in repo.\n\nInsecure patterns:\n\n* No security headers anywhere (app or edge).\n* CSP missing on apps that render untrusted content or use third-party scripts.\n\nDetection hints:\n\n* Check server/CDN config in repo (nginx, Cloudflare, Vercel config, etc.).\n* If absent, flag as “verify at runtime/edge”.\n\nFix:\n\n* Set headers centrally at the edge.\n* Keep CSP realistic and iterative (report-only → enforce).\n\nNotes:\n\n* MDN clickjacking guidance discusses defenses including `X-Frame-Options` and CSP `frame-ancestors`. ([MDN Web Docs][8])\n* OWASP CSP guidance explains delivery via response headers and recommends headers as the preferred mechanism. ([OWASP Cheat Sheet Series][2])\n\n---\n\n### REACT-POSTMSG-001: `postMessage` must validate origin and treat payload as untrusted data\n\nSeverity: Medium to High (depends on what messages can do)\n\nRequired:\n\n* MUST specify exact `targetOrigin` when sending messages (not `*`) unless there is a strict reason.\n* MUST validate `event.origin` on receipt and validate message shape.\n* MUST NOT evaluate message data as code or insert it into the DOM as HTML.\n\nInsecure patterns:\n\n* `window.postMessage(data, '*')` to unknown targets.\n* Receiving:\n\n  * `window.addEventListener('message', (e) => { eval(e.data) })`\n  * `element.innerHTML = e.data`\n\nDetection hints:\n\n* Search: `postMessage(`, `addEventListener('message'`\n* Check for origin checks and safe handling.\n\nFix:\n\n* Add strict origin allowlists and schema validation (e.g., zod).\n* Treat message payload strictly as data; render safely via React.\n\nNotes:\n\n* OWASP HTML5 guidance recommends specifying expected origin for `postMessage`, checking sender origin, validating data, and avoiding eval/innerHTML with message content. ([OWASP Cheat Sheet Series][4])\n\n---\n\n### REACT-FILE-001: File uploads and previews must not create client-side active content vulnerabilities\n\nSeverity: Medium (can be High if stored-XSS possible)\n\nRequired:\n\n* MUST treat user-uploaded files and previews as potentially malicious.\n* MUST NOT render uploaded HTML/SVG/other active content inline unless sanitized and explicitly required.\n* SHOULD validate file types client-side for UX, but MUST rely on server-side validation for security.\n\nInsecure patterns:\n\n* Rendering user-uploaded HTML as content.\n* Inline rendering of untrusted SVG/HTML via `dangerouslySetInnerHTML` or `<iframe srcdoc=...>` without sanitization.\n\nDetection hints:\n\n* Search for upload components and preview logic:\n\n  * `input type=\"file\"`, `FileReader`, `URL.createObjectURL`, `<iframe>`, `<object>`, `<embed>`.\n* Trace where uploaded content is later displayed.\n\nFix:\n\n* Restrict accepted types, sanitize where needed, and prefer download/attachment flows for risky types.\n* Ensure server enforces the real policy (type checking, renaming, scanning, storing outside webroot).\n\nNotes:\n\n* OWASP file upload guidance highlights allowlisting extensions, validating file type, generating filenames, limiting size, storing outside webroot, and considering “client-side active content (XSS, CSRF, etc.)” when files are publicly retrievable. ([OWASP Cheat Sheet Series][19])\n\n---\n\n### REACT-SUPPLY-001: Dependency and supply-chain hygiene (frontend + build tooling)\n\nSeverity: Low\n\nRequired:\n\n* MUST use a lockfile and enforce reproducible installs in CI.\n* SHOULD regularly audit dependencies and respond quickly to advisories for:\n\n  * React, react-dom, router libs, build tooling (Vite/Webpack), sanitizers, auth libs, etc.\n* SHOULD reduce exposure to install-time script attacks and typosquatting risk.\n\nAudit focus:\n\n* CI should use `npm ci` (or Yarn frozen lockfile / pnpm equivalent) to prevent drift.\n* Use vulnerability scanning (`npm audit`, GitHub Dependabot/alerts, etc.).\n\nInsecure patterns:\n\n* No lockfile or lockfile ignored in CI.\n* `npm install` in CI producing non-reproducible builds.\n* Unpinned or unreviewed high-risk deps; sudden major updates without review.\n* Blindly running install scripts from third-party packages.\n\nDetection hints:\n\n* Check for lockfiles: `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`.\n* Check CI scripts for `npm install` vs `npm ci`.\n* Search for `postinstall` scripts and suspicious build steps.\n\nFix:\n\n* Use lockfile and enforce it in CI (e.g., `npm ci`).\n* Run audits regularly; pin/upgrade responsibly.\n* Consider restricting install scripts where feasible.\n\nNotes:\n\n* npm docs describe `npm audit` as submitting the project dependency tree to the registry to receive a report of known vulnerabilities and (optionally) applying remediations via `npm audit fix`, while noting some vulns require manual review. ([npm Docs][20])\n* npm docs describe `npm ci` as intended for automated/CI environments, requiring an existing lockfile and failing if `package.json` and lockfile do not match. ([npm Docs][21])\n* OWASP NPM security guidance recommends enforcing the lockfile and explicitly calls out `npm ci` / `yarn install --frozen-lockfile` to abort on inconsistencies, and highlights the risk of install-time scripts and the option to use `--ignore-scripts` to reduce attack surface. ([OWASP Cheat Sheet Series][22])\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* Raw HTML / XSS escape hatches:\n\n  * `dangerouslySetInnerHTML`, `__html:`\n  * Markdown HTML passthrough flags: `rehype-raw`, `allowDangerousHtml`, `sanitize: false`\n* DOM XSS sinks:\n\n  * `innerHTML`, `outerHTML`, `insertAdjacentHTML`, `document.write`, `DOMParser`, `createContextualFragment`\n* Dangerous JS execution:\n\n  * `eval(`, `new Function(`, `setTimeout(\"`, `setInterval(\"`\n* Untrusted URL injection / navigation:\n\n  * `href={` / `src={` with untrusted values\n  * `window.location`, `location.href`, `window.open`, `navigate(`\n  * Query params: `next`, `returnTo`, `redirect`\n* Token/session risk:\n\n  * `localStorage.setItem`, `sessionStorage.setItem`, `getItem(` with `token`, `jwt`, `refresh`\n* Cookie/CSRF coupling:\n\n  * `credentials: 'include'`, `withCredentials: true` on state-changing requests without CSRF headers\n* Third-party scripts:\n\n  * `<script src=...>` in `public/index.html`\n  * Tag manager snippets and dynamic script insertion\n* Service workers:\n\n  * `navigator.serviceWorker.register`, Workbox usage, custom `fetch` handlers\n* postMessage:\n\n  * `postMessage(` with `*`, missing `event.origin` checks\n* Supply chain:\n\n  * Missing lockfile, CI uses `npm install`, no audit step, risky postinstall scripts\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (React escape hatch vs DOM sink vs navigation vs storage)\n* protective controls present (sanitization, allowlists, CSP/Trusted Types, CSRF tokens, headers, governance)\n\n---\n\n## 6) Sources (accessed 2026-01-26)\n\nPrimary React documentation:\n\n* React 19 stable announcement — `https://react.dev/blog/2024/12/05/react-19` ([React][23])\n* React DOM docs: `dangerouslySetInnerHTML` warning — `https://react.dev/reference/react-dom/components/common#dangerouslysetting-the-inner-html` ([React][12])\n* React (legacy) JSX escaping statement — `https://legacy.reactjs.org/docs/introducing-jsx.html` ([React][14])\n\nOWASP Cheat Sheet Series:\n\n* Cross Site Scripting Prevention (framework escape hatches; React `dangerouslySetInnerHTML`; URL validation notes) — `https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][9])\n* Content Security Policy — `https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][2])\n* Cross-Site Request Forgery Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][6])\n* HTML5 Security (Web Storage, postMessage, tabnabbing, sandboxed frames) — `https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][4])\n* Third Party JavaScript Management — `https://cheatsheetseries.owasp.org/cheatsheets/Third_Party_Javascript_Management_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][5])\n* File Upload — `https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][19])\n* NPM Security best practices — `https://cheatsheetseries.owasp.org/cheatsheets/NPM_Security_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][22])\n\nBrowser / platform references (MDN, W3C):\n\n* Trusted Types API — `https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API` ([MDN Web Docs][3])\n* W3C Trusted Types spec — `https://www.w3.org/TR/trusted-types/` ([W3C][15])\n* Subresource Integrity — `https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity` ([MDN Web Docs][7])\n* Clickjacking defenses overview — `https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/Clickjacking` ([MDN Web Docs][8])\n* Using Service Workers (HTTPS requirement; proxy-like behavior) — `https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers` ([MDN Web Docs][10])\n* Secure contexts (powerful APIs restricted to HTTPS) — `https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Secure_Contexts` ([MDN Web Docs][18])\n* Link `rel` values (noopener/noreferrer) — `https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel` ([MDN Web Docs][17])\n\nBuild tooling / env exposure references:\n\n* Create React App env variables warning — `https://create-react-app.dev/docs/adding-custom-environment-variables/` ([create-react-app.dev][1])\n* Vite env variables security notes — `https://vite.dev/guide/env-and-mode` ([vitejs][11])\n\nAuth/token storage guidance:\n\n* OAuth 2.0 for Browser-Based Apps (token storage discussion) — `https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps` ([IETF Datatracker][16])\n\nDependency tooling references:\n\n* npm audit docs — `https://docs.npmjs.com/cli/v10/commands/npm-audit/` ([npm Docs][20])\n* npm ci docs — `https://docs.npmjs.com/cli/v10/commands/npm-ci/` ([npm Docs][21])\n\nSanitizer reference:\n\n* DOMPurify — `https://github.com/cure53/DOMPurify` ([GitHub][13])\n\n[1]: https://create-react-app.dev/docs/adding-custom-environment-variables/ \"Adding Custom Environment Variables | Create React App\"\n[2]: https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html \"Content Security Policy - OWASP Cheat Sheet Series\"\n[3]: https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API \"Trusted Types API - Web APIs | MDN\"\n[4]: https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html \"HTML5 Security - OWASP Cheat Sheet Series\"\n[5]: https://cheatsheetseries.owasp.org/cheatsheets/Third_Party_Javascript_Management_Cheat_Sheet.html \"Third Party Javascript Management - OWASP Cheat Sheet Series\"\n[6]: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html \"Cross-Site Request Forgery Prevention - OWASP Cheat Sheet Series\"\n[7]: https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity \"Subresource Integrity - Security | MDN\"\n[8]: https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/Clickjacking \"Clickjacking - Security | MDN\"\n[9]: https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html \"Cross Site Scripting Prevention - OWASP Cheat Sheet Series\"\n[10]: https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers \"Using Service Workers - Web APIs | MDN\"\n[11]: https://vite.dev/guide/env-and-mode \"Env Variables and Modes | Vite\"\n[12]: https://react.dev/reference/react-dom/components/common \"Common components (e.g. <div>) – React\"\n[13]: https://github.com/cure53/DOMPurify \"GitHub - cure53/DOMPurify: DOMPurify - a DOM-only, super-fast, uber-tolerant XSS sanitizer for HTML, MathML and SVG. DOMPurify works with a secure default, but offers a lot of configurability and hooks. Demo:\"\n[14]: https://legacy.reactjs.org/docs/introducing-jsx.html \"Introducing JSX – React\"\n[15]: https://www.w3.org/TR/trusted-types/ \"Trusted Types\"\n[16]: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps \"\n\n                draft-ietf-oauth-browser-based-apps-26\n\n        \"\n[17]: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel \"HTML attribute: rel - HTML | MDN\"\n[18]: https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Secure_Contexts \"Secure contexts - Security | MDN\"\n[19]: https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html \"File Upload - OWASP Cheat Sheet Series\"\n[20]: https://docs.npmjs.com/cli/v10/commands/npm-audit \"npm-audit | npm Docs\"\n[21]: https://docs.npmjs.com/cli/v10/commands/npm-ci \"npm-ci | npm Docs\"\n[22]: https://cheatsheetseries.owasp.org/cheatsheets/NPM_Security_Cheat_Sheet.html \"NPM Security - OWASP Cheat Sheet Series\"\n[23]: https://react.dev/blog/2024/12/05/react-19 \"React v19 – React\"\n","isInternal":false,"tokens":9638,"sizeBytes":41662},{"name":"javascript-typescript-vue-web-frontend-security.md","path":"core/skills/builtin/security-best-practices/references/javascript-typescript-vue-web-frontend-security.md","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/security-best-practices/references/javascript-typescript-vue-web-frontend-security.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Vue.js Web Security Spec (Vue 3.x, TypeScript/JavaScript, common tooling: Vite)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new Vue code.\n2. **Security review / vulnerability hunting** in existing Vue code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session cookies, auth tokens).\n* MUST NOT “fix” security by disabling protections (e.g., weakening CSP, turning on unsafe template compilation, using `v-html` as a shortcut, bypassing backend auth, or “just store the token in localStorage”).\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and configuration values that justify the claim.\n* MUST treat uncertainty honestly: if a protection might exist at the edge (CDN, reverse proxy, WAF, server headers), report it as “not visible in repo; verify runtime/infra config”.\n* MUST remember the frontend trust model: **any code shipped to browsers is attacker-readable and attacker-modifiable**. Secrets and “security enforcement” cannot rely on frontend-only logic.\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new Vue code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default framework features and proven libraries over custom security code.\n* MUST avoid introducing new risky sinks (runtime template compilation, `v-html` / `innerHTML`, unsafe URL navigation, dynamic script injection, etc.). ([Vue.js][1])\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a Vue repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. Build/deploy entrypoints and hosting config (Docker, CI, static hosting, SSR server).\n2. Secrets exposure (env usage, `.env*`, hard-coded keys). ([vitejs][2])\n3. XSS surface: templates, `v-html` / `innerHTML`, URL/style injection, DOM APIs. ([Vue.js][1])\n4. Auth/session handling in the browser (token storage, credentialed requests, CSRF integration). ([Vue.js][1])\n5. Routing/navigation (open redirects, “return_to/next”, unsafe external navigation). ([Vue.js][1])\n6. Third-party scripts and content (CDN assets, analytics, widgets, iframes). ([Vue.js][1])\n7. Security headers and browser hardening expectations (CSP, clickjacking). ([Vue.js][1])\n8. SSR-specific concerns (state serialization, template boundaries) when applicable. ([Vue.js][1])\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nIn a Vue app, untrusted input includes (non-exhaustive):\n\n* Anything from APIs: `fetch`, `axios`, GraphQL responses, webhooks, third-party SDKs.\n* Router-controlled data: `route.params`, `route.query`, `route.hash`, and anything derived from `window.location`.\n* User-controlled persisted content: DB-backed content displayed in the UI (comments, profiles, CMS content).\n* Browser-controlled storage: `localStorage`, `sessionStorage`, `IndexedDB`.\n* Cross-window messages: `postMessage` inputs.\n* Anything that can be influenced by an attacker through DOM clobbering or injected HTML (especially if Vue is mounted onto non-sterile DOM). ([Vue.js][1])\n\n### 2.2 State-changing action (frontend perspective)\n\nAn action is state-changing if it can:\n\n* Create/update/delete data via API calls.\n* Change authentication/session state (login, logout, refresh token).\n* Trigger privileged operations (payments, admin actions).\n* Cause side effects (sending emails, triggering webhooks, changing account settings).\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + component/function + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common Vue/front-end misconfigurations.\n\n* MUST ship a **production build** (not a development build or dev server). ([Vue.js][3])\n* MUST NOT ship secrets in frontend bundles; treat all client-exposed env variables as public. ([vitejs][2])\n* MUST NOT render non-trusted templates or allow user-provided Vue templates (equivalent to arbitrary JS execution). ([Vue.js][1])\n* SHOULD avoid raw HTML injection (`v-html`, `innerHTML`) unless content is trusted or strongly sandboxed. ([Vue.js][1])\n* SHOULD deploy baseline security headers (especially CSP and clickjacking defenses) at the server/CDN layer. ([OWASP Cheat Sheet Series][4])\n* SHOULD use safe auth patterns (prefer HttpOnly cookies for session tokens; coordinate with backend on CSRF). ([Vue.js][1])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### VUE-DEPLOY-001: Do not run dev/preview servers in production\n\nSeverity: High\n\nRequired:\n\n* MUST NOT deploy the Vite/Vue dev server (`vite`, `npm run dev`, HMR) as the production server.\n* MUST NOT use `vite preview` as a production server. ([vitejs][5])\n* MUST build (`vite build`) and serve the built assets using a production-grade static server/CDN, or a production SSR server if you are doing SSR. ([vitejs][6])\n\nInsecure patterns:\n\n* Docker/Procfile/systemd running `vite`, `npm run dev`, or `vite preview` as the production entrypoint.\n* Publicly exposed HMR endpoints.\n\nDetection hints:\n\n* Search: `vite`, `npm run dev`, `pnpm dev`, `yarn dev`, `vite preview`, `vue-cli-service serve`.\n* Check Docker `CMD`, `ENTRYPOINT`, CI deploy scripts, platform config.\n\nFix:\n\n* Build artifacts with `vite build`.\n* Serve `dist/` with hardened hosting (CDN/static server) or integrate into your backend server as static assets.\n\nNotes:\n\n* Using dev/preview servers locally is fine; only flag if it is the production entrypoint.\n\n---\n\n### VUE-DEPLOY-002: Use Vue production builds and keep devtools off in production\n\nSeverity: Medium (High if production devtools/debug hooks are enabled)\n\nRequired:\n\n* If loading Vue from CDN/self-host without a bundler, MUST use the `.prod.js` builds in production. ([Vue.js][3])\n* SHOULD ensure production bundles do not enable Vue devtools in production builds, and SHOULD not intentionally enable production devtools flags. ([Vue.js][7])\n\nInsecure patterns:\n\n* Production includes development build artifacts.\n* Explicitly enabling production devtools/diagnostic hooks.\n\nDetection hints:\n\n* Search HTML for `vue.global.js` / non-`.prod.js` variants when using CDN builds.\n* Search build config for Vue feature flags like `__VUE_PROD_DEVTOOLS__`. ([Vue.js][7])\n\nFix:\n\n* Switch to production build artifacts and ensure compile-time flags are configured for production.\n\n---\n\n### VUE-SECRETS-001: Never ship secrets in frontend code or env variables\n\nSeverity: High (Critical if real credentials are exposed)\n\nRequired:\n\n* MUST treat all frontend code and configuration as public.\n* MUST NOT embed secrets in:\n\n  * source code\n  * `.env` files committed to repo\n  * `import.meta.env.*` variables included in the bundle\n* MUST assume any env var that ends up in the client bundle is attacker-readable. ([vitejs][2])\n\nInsecure patterns:\n\n* `VITE_API_KEY=...` containing a true secret (not just a public identifier).\n* Hard-coded API keys, private tokens, service credentials, signing keys in JS/TS.\n\nDetection hints:\n\n* Search: `VITE_`, `import.meta.env`, `.env`, `.env.production`, `.env.*.local`.\n* Grep for `API_KEY`, `SECRET`, `TOKEN`, `PRIVATE_KEY`, `BEGIN`, `sk-`, `AKIA`, etc.\n\nFix:\n\n* Move secrets to backend/edge functions.\n* Use backend-minted short-lived tokens for the browser when needed.\n\nNotes:\n\n* Vite specifically warns that `.env.*.local` should be gitignored and that `VITE_*` vars end up in the client bundle, so they must not contain sensitive info. ([vitejs][2])\n\n---\n\n### VUE-SECRETS-002: Do not broaden Vite env exposure\n\nSeverity: High\n\nRequired:\n\n* MUST NOT configure Vite to expose all environment variables to the client.\n* SHOULD keep `envPrefix` strict and explicit.\n\nInsecure patterns:\n\n* Setting `envPrefix` to overly broad values (or `''`) to “make env vars work”.\n* Custom scripts that inject server secrets into global variables in HTML at build time.\n\nDetection hints:\n\n* Check `vite.config.*` for `envPrefix`.\n* Look for `define: { 'process.env': ... }` or manual injection into `window.__CONFIG__`.\n\nFix:\n\n* Keep secrets server-side.\n* Only expose non-sensitive values intentionally designed to be public.\n\nNotes:\n\n* Vite’s docs explain that only prefixed variables are exposed and that exposed variables land in the client bundle. ([vitejs][2])\n\n---\n\n### VUE-XSS-001: Prefer Vue’s default escaping; avoid raw HTML injection\n\nSeverity: High\n\nRequired:\n\n* MUST rely on Vue’s automatic escaping for text interpolation and attribute binding where possible. ([Vue.js][1])\n* MUST NOT render user-provided HTML via:\n\n  * `v-html`\n  * `innerHTML` in render functions / JSX\n  * direct DOM APIs (`element.innerHTML`, `insertAdjacentHTML`)\n    unless the HTML is trusted or robustly sanitized and the risk is explicitly accepted. ([Vue.js][1])\n\nInsecure patterns:\n\n* `<div v-html=\"userProvidedHtml\"></div>`\n* `h('div', { innerHTML: userProvidedHtml })`\n* `<div innerHTML={userProvidedHtml}></div>`\n* `el.innerHTML = untrusted`\n\nDetection hints:\n\n* Search: `v-html`, `innerHTML`, `insertAdjacentHTML`, `DOMParser`, `document.write`.\n\nFix:\n\n* Render untrusted content as text (interpolation).\n* If HTML rendering is required (e.g., Markdown), sanitize with a well-maintained HTML sanitizer and apply defense-in-depth (CSP, Trusted Types). ([Vue.js][1])\n\nNotes:\n\n* Vue’s docs explicitly warn that user-provided HTML is never “100% safe” unless sandboxed or strictly self-only exposure. ([Vue.js][1])\n\n---\n\n### VUE-XSS-002: Never use non-trusted templates (client-side template/code injection)\n\nSeverity: Critical\n\nRequired:\n\n* MUST NOT use non-trusted content as a Vue component template.\n* MUST treat “user can write a Vue template” as “user can execute arbitrary JavaScript in your app”, and potentially in SSR contexts too. ([Vue.js][1])\n* SHOULD prefer the runtime-only build (templates compiled at build time) and avoid shipping the runtime compiler unless you have a vetted need.\n\nInsecure patterns:\n\n* `createApp({ template: '<div>' + userProvidedString + '</div>' }).mount(...)`\n* Storing templates in DB and compiling/rendering them in the browser.\n* Admin/CMS features that allow entering Vue template syntax.\n\nDetection hints:\n\n* Search: `template:` where the value is not a static string.\n* Search: `@vue/compiler-dom`, `compile(`, “runtime compiler” build selection, dynamic SFC compilation.\n* Search for “template editor”, “custom template”, “theme HTML” features.\n\nFix:\n\n* Treat templates as code: keep them developer-controlled.\n* If end-user customization is required, use a safe format (restricted Markdown subset) rendered via a sanitizer, or isolate in a sandboxed iframe.\n\n---\n\n### VUE-XSS-003: Do not mount Vue onto DOM that may contain user-provided server-rendered HTML\n\nSeverity: Medium\n\nRequired:\n\n* MUST NOT mount Vue on nodes that may contain server-rendered and user-provided content (because attacker-controlled HTML that is “safe as HTML” may become unsafe as a Vue template). ([Vue.js][1])\n* SHOULD mount Vue into a “sterile” root element and render the app’s DOM from Vue-controlled templates/components.\n\nInsecure patterns:\n\n* Server renders user content into `#app`, then Vue mounts on `#app` and compiles/interprets that DOM as a template.\n* “Sprinkling Vue” on large server-rendered pages that include user-generated content.\n\nDetection hints:\n\n* Check server templates (e.g., Rails/Django/Express templates) for user HTML inserted inside the Vue mount root.\n* Look for `mount('#app')` where `#app` includes server-rendered UGC.\n\nFix:\n\n* Move user-rendered HTML outside the Vue mount root, or render it in a safe way (text/sanitized HTML) from Vue components.\n\n---\n\n### VUE-XSS-004: Prevent URL injection in bindings and navigations\n\nSeverity: High\n\nRequired:\n\n* MUST validate/sanitize any user-influenced URL before binding to navigation sinks (`href`, `src`, `action`, `window.location`, `window.open`, router navigation to external).\n* MUST specifically prevent `javascript:` URL execution in bindings like `<a :href=\"userProvidedUrl\">`. ([Vue.js][1])\n* SHOULD validate protocol and destination (allowlist `https:` and expected hosts; allow `mailto:`/`tel:` only if intended).\n\nInsecure patterns:\n\n* `<iframe :src=\"userProvidedUrl\">`\n* `window.location = route.query.next`\n* `window.open(userProvidedUrl)`\n\nDetection hints:\n\n* Search: `:href=`, `:src=`, `window.location`, `location.href`, `window.open`, `router.push(` with untrusted input.\n* Look for `next`, `return_to`, `redirect` query params.\n\nFix:\n\n* Prefer internal navigation via route names/paths you control.\n* For external URLs: parse with `new URL(...)`, allowlist protocol/host, reject `javascript:` and other dangerous schemes.\n* Sanitize and validate on the backend before storing user URLs (Vue docs explicitly recommend backend sanitization). ([Vue.js][1])\n\n---\n\n### VUE-XSS-005: Prevent style/CSS injection and UI redress\n\nSeverity: Low\n\nRequired:\n\n* MUST NOT bind attacker-controlled CSS strings broadly (e.g., `:style=\"userProvidedStyles\"`).\n* SHOULD use Vue’s style object syntax and only allow safe, specific properties if user customization is needed. ([Vue.js][1])\n* SHOULD isolate “user can control layout/CSS” features inside sandboxed iframes.\n\nInsecure patterns:\n\n* `:style=\"userProvidedStyles\"` where styles are attacker-controlled.\n* Rendering user-provided `<style>` content (even if Vue blocks some patterns, don’t try to work around it).\n\nDetection hints:\n\n* Search: `:style=\"` bound to non-constant variables that originate from API/user content.\n* Search for “custom CSS”, “theme editor”, “profile CSS”.\n\nFix:\n\n* Allowlist properties and values; avoid raw style strings.\n* Use sandboxed iframes for rich user customization.\n\n---\n\n### VUE-XSS-006: Never bind user-provided JavaScript into event handler attributes\n\nSeverity: Critical\n\nRequired:\n\n* MUST NOT bind attacker-provided strings into event handler attributes (e.g., `onclick`, `onfocus`, etc.).\n* MUST treat “user-provided JS” as unsafe unless sandboxed and self-only exposure is guaranteed. ([Vue.js][1])\n\nInsecure patterns:\n\n* `<div :onclick=\"userProvidedString\">`\n* `<a :onmouseenter=\"userProvidedString\">`\n\nDetection hints:\n\n* Search: `:on` followed by event attribute names (`:onclick`, `:onload`, etc.).\n* Search for `setAttribute('on` patterns.\n\nFix:\n\n* Use real event listeners with developer-controlled handlers.\n* If you truly need user scripting, isolate it (sandboxed iframe + strict boundaries).\n\n---\n\n### VUE-ROUTER-001: Do not treat client-side route guards as authorization\n\nSeverity: High\n\nRequired:\n\n* MUST NOT rely on Vue Router guards, UI hiding, or client-side checks to enforce authorization.\n* MUST enforce authorization on the backend for every privileged action and sensitive data response. ([OWASP Cheat Sheet Series][8])\n\nInsecure patterns:\n\n* “Admin route is protected because `beforeEach` checks `user.isAdmin`.”\n* Sensitive API endpoints that assume “the frontend won’t call this unless allowed.”\n\nDetection hints:\n\n* Search `router.beforeEach` for role-based gating and see if the backend is also enforcing.\n* Look for “security by route meta” patterns (`meta.requiresAdmin`) with no server corroboration.\n\nFix:\n\n* Keep route guards as UX only (reduce accidental access), but enforce real checks server-side.\n\n---\n\n### VUE-ROUTER-002: Prevent open redirects and unsafe “return_to/next” handling\n\nSeverity: Low\n\nRequired:\n\n* MUST validate redirect destinations derived from untrusted input (`next`, `return_to`, `redirect`).\n* SHOULD allow only same-site relative paths or an explicit allowlist of destinations.\n* MUST NOT allow non `http` / `https` protos (such as `javascript:`)\n\nInsecure patterns:\n\n* `router.push(route.query.next as string)`\n* `window.location.href = route.query.redirect`\n\nDetection hints:\n\n* Search for `route.query.next`, `route.query.redirect`, `return_to`, `continue`, `callback`.\n* Trace the value into router/window navigation sinks.\n\nFix:\n\n* Allow only relative paths starting with `/` (and reject `//host`, `javascript:`, etc.).\n* Prefer redirecting to named routes you control.\n\nNotes:\n\n* Even Vue’s docs note that sanitized URLs still may not guarantee safe destinations. ([Vue.js][1])\n\n---\n\n### VUE-AUTH-001: Token storage must assume XSS is possible\n\nSeverity: Low\n\nRequired:\n\n* MUST assume any token accessible to JavaScript can be stolen via XSS.\n* SHOULD prefer HttpOnly cookies (set by the backend) for session tokens, combined with CSRF protections where relevant. ([Vue.js][1])\n* SHOULD avoid storing long-lived tokens (especially refresh tokens) in `localStorage`/`sessionStorage`.\n\nInsecure patterns:\n\n* `localStorage.setItem('token', ...)` for long-lived bearer tokens.\n* Storing refresh tokens in JS-accessible storage.\n\nDetection hints:\n\n* Search: `localStorage`, `sessionStorage`, `indexedDB`, `persist`, `pinia-plugin-persistedstate`.\n* Identify whether stored values are auth/session material.\n\nFix:\n\n* Prefer backend-managed sessions via HttpOnly cookies.\n* If bearer tokens are unavoidable, keep them short-lived, stored in memory, and rotate frequently; combine with strong XSS mitigations (CSP, Trusted Types, strict sanitization). ([OWASP Cheat Sheet Series][4])\n\n---\n\n### VUE-CSRF-001: Coordinate with the backend for CSRF when using cookies\n\nSeverity: High (for cookie-authenticated state-changing requests)\n\nNOTE: If the application is not using cookie based authentication (for example if it passes an Authorization header), then CSRF is not a concern\n\nRequired:\n\n* If API requests include cookies (`credentials: 'include'` / `withCredentials: true`) and cookies authenticate the user, MUST include CSRF protections coordinated with the backend (token/header patterns, Origin checks, SameSite cookies as defense-in-depth). ([Vue.js][1])\n* MUST NOT “solve CORS/CSRF errors” by disabling protections on the backend or using `mode: 'no-cors'` on the frontend.\n\nInsecure patterns:\n\n* `fetch(url, { credentials: 'include', method: 'POST', body: ... })` with no CSRF token/header usage anywhere.\n* Enabling cross-origin credentialed requests without strict origin allowlists (backend-side).\n\nDetection hints:\n\n* Search: `credentials: 'include'`, `withCredentials`, `xsrf`, `csrf`, `X-CSRF-Token`, `X-XSRF-TOKEN`.\n* Look at API wrapper modules for headers and cookie settings.\n\nFix:\n\n* Implement backend-issued CSRF tokens and require them on state-changing requests.\n* Keep cookies `SameSite=Lax/Strict` where compatible and verify Origin/Referer where appropriate (backend-driven). ([OWASP Cheat Sheet Series][9])\n\nNotes:\n\n* Vue’s docs explicitly say CSRF is primarily backend-addressed but recommends coordinating on CSRF token submission. ([Vue.js][1])\n\n---\n\n### VUE-HTTP-001: Do not put secrets in URLs; avoid leaking sensitive data in navigation/logs\n\nSeverity: Medium\n\nRequired:\n\n* MUST NOT place tokens/secrets in query strings or fragments (they leak via logs, referrers, browser history).\n* SHOULD avoid logging sensitive values to console in production.\n\nInsecure patterns:\n\n* `/?token=...`, `/#access_token=...` used beyond short-lived OAuth handoff.\n* `console.log(userSession)` that includes tokens/PII.\n\nDetection hints:\n\n* Search for `token=` in router parsing, auth callback handlers, and analytics logs.\n* Search for `console.log(` around auth code.\n\nFix:\n\n* Use Authorization headers or HttpOnly cookies.\n* Scrub logs; gate debug logs behind dev-only checks.\n\n---\n\n### VUE-HEADERS-001: Require security headers at the deployment layer\n\nSeverity: Medium\n\nRequired:\n\n* SHOULD deploy a CSP (`Content-Security-Policy`) suitable for your Vue app.\n* SHOULD deploy clickjacking defenses (CSP `frame-ancestors` and/or `X-Frame-Options`) unless intentional embedding is required.\n* SHOULD deploy `X-Content-Type-Options: nosniff`, plus other headers as appropriate (Referrer-Policy, Permissions-Policy). ([OWASP Cheat Sheet Series][4])\n\nInsecure patterns:\n\n* No evidence of headers in server/CDN config for an app with UGC or rich HTML rendering.\n* CSP includes `unsafe-inline`/`unsafe-eval` without strong justification.\n\nDetection hints:\n\n* Look for hosting config: nginx, Netlify/Vercel headers config, CloudFront/Cloudflare rules.\n* If absent in repo, flag as “verify at edge”.\n\nFix:\n\n* Set headers at the edge or in the server. Start with a conservative CSP and tighten.\n\n---\n\n### VUE-CSP-001: Use Trusted Types and DOM XSS hardening when feasible\n\nSeverity: Low\n\nRequired:\n\n* For apps with significant DOM injection surface (rich text, plugins, `v-html`), SHOULD consider enabling Trusted Types to reduce DOM XSS risk. ([web.dev][10])\n* SHOULD treat Trusted Types as defense-in-depth, not a replacement for sanitization.\n\nInsecure patterns:\n\n* Frequent use of `innerHTML`/`v-html` without sanitization or CSP hardening.\n\nDetection hints:\n\n* Search: `v-html`, `innerHTML`, `insertAdjacentHTML`.\n* Check CSP for `require-trusted-types-for 'script'` usage (if headers are in repo).\n\nFix:\n\n* Reduce/centralize HTML injection, sanitize inputs, and add Trusted Types policies where appropriate.\n\n---\n\n### VUE-THIRDPARTY-001: Avoid dynamic third-party script injection; prefer static, vetted loading\n\nSeverity: Low\n\nRequired:\n\n* MUST NOT inject `<script src=\"...\">` where the URL is user-controlled.\n* SHOULD treat third-party widgets/analytics as supply-chain risk; load only from vetted, pinned sources.\n\nInsecure patterns:\n\n* `const s=document.createElement('script'); s.src = userProvidedUrl; ...`\n* “Plugin marketplace” that loads arbitrary remote scripts.\n\nDetection hints:\n\n* Search: `createElement('script')`, `.src =`, `appendChild(script)`.\n* Search for “loadExternalScript”, “injectScript”, “cdnUrl”.\n\nFix:\n\n* Bundle dependencies, or allowlist strict origins and enforce integrity (see SRI rule).\n* Consider sandboxed iframes for untrusted third-party UI.\n\n---\n\n### VUE-SRI-001: Use Subresource Integrity for CDN-hosted scripts/styles\n\nSeverity: Low\n\nRequired:\n\n* If loading scripts/styles from a CDN, SHOULD use Subresource Integrity (`integrity` attribute) with appropriate `crossorigin` configuration. ([MDN Web Docs][11])\n* SHOULD prefer self-hosting or bundling over runtime CDN dependencies for security-critical code.\n\nInsecure patterns:\n\n* `<script src=\"https://cdn.example/...\">` with no `integrity`.\n* Remote script URLs that can change content without version pinning.\n\nDetection hints:\n\n* Search `index.html` and server templates for `https://` script/style tags.\n* Check for `integrity=`.\n\nFix:\n\n* Add SRI hashes (and pin versions), or bundle assets with your build.\n\n---\n\n### VUE-SUPPLY-001: Dependency and patch hygiene is mandatory\n\nSeverity: Low\n\nRequired:\n\n* SHOULD keep Vue and official companion libraries updated; Vue explicitly recommends using latest versions to remain as secure as possible. ([Vue.js][1])\n* MUST respond to security advisories promptly.\n* SHOULD pin dependencies and keep lockfiles committed (to reduce drift in production artifacts).\n\nInsecure patterns:\n\n* Outdated major versions with known CVEs.\n* No lockfile in repo; wide semver ranges for critical deps.\n* Ignoring advisories for template/rendering/compiler packages.\n\nDetection hints:\n\n* Inspect `package.json`, lockfiles, CI install commands.\n* Search for `npm audit` disabled, “ignore vulnerabilities” scripts.\n\nFix:\n\n* Upgrade dependencies and add regression tests around the impacted behavior.\n* Add dependency scanning in CI.\n\n---\n\n### VUE-SSR-001: SSR adds additional trust boundaries; treat state injection as XSS-sensitive\n\nSeverity: Medium\n\nRequired:\n\n* When using SSR, MUST treat anything injected into the HTML document (initial state, serialized data, inline scripts) as XSS-sensitive.\n* MUST keep the “trusted templates only” rule even stricter, because unsafe templates can lead to server-side execution during rendering. ([Vue.js][1])\n* SHOULD follow Vue SSR documentation and best practices for SSR security. ([Vue.js][1])\n\nInsecure patterns:\n\n* Concatenating untrusted strings into SSR templates.\n* Injecting JSON into `<script>` blocks without robust escaping/serialization controls.\n\nDetection hints:\n\n* Search server code for `__INITIAL_STATE__`, `window.__*STATE__`, template concatenation, and SSR render pipelines.\n* Trace untrusted data into those sinks.\n\nFix:\n\n* Use safe serialization patterns recommended by your SSR stack.\n* Avoid rendering untrusted HTML; sanitize or isolate.\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* Dev/preview servers in production:\n\n  * `npm run dev`, `vite`, `vite preview`, `vue-cli-service serve` ([vitejs][5])\n* Secrets exposure:\n\n  * `.env`, `.env.production`, `.env.*.local`, `VITE_`, `import.meta.env`, hard-coded `API_KEY` / `SECRET` ([vitejs][2])\n* XSS sinks:\n\n  * `v-html`, `innerHTML`, `insertAdjacentHTML`, `DOMParser`, `document.write` ([Vue.js][1])\n* Client-side template injection:\n\n  * `template:` concatenation, `compile(`, runtime compiler usage, mounting on non-sterile DOM ([Vue.js][1])\n* URL injection / open redirects:\n\n  * `:href=\"...\"` / `:src=\"...\"` from user data\n  * `javascript:` occurrences\n  * `route.query.next` / `redirect` / `return_to` flowing into `router.push` or `window.location` ([Vue.js][1])\n* Style injection:\n\n  * `:style=\"userProvidedStyles\"` or user-driven theme CSS ([Vue.js][1])\n* Token storage:\n\n  * `localStorage.setItem('token'...)`, persisted auth stores, refresh tokens in JS-accessible storage\n* CSRF integration red flags:\n\n  * `credentials: 'include'` / `withCredentials: true` without any CSRF header/token handling ([Vue.js][1])\n* Third-party scripts:\n\n  * dynamic script injection (`createElement('script')`), CDN scripts without SRI ([MDN Web Docs][11])\n* External links security:\n\n  * `target=\"_blank\"` without `rel=\"noopener\"`/`noreferrer` (still recommended for legacy and explicitness) ([MDN Web Docs][12])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (HTML/DOM insertion, template compilation, URL navigation, style injection, script injection)\n* protective controls present (sanitization, allowlists, CSP/Trusted Types, backend validation)\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary Vue documentation:\n\n* Vue Docs: Security — `https://vuejs.org/guide/best-practices/security` ([Vue.js][1])\n* Vue Docs: Template Syntax (security warning about in-DOM templates) — `https://vuejs.org/guide/essentials/template-syntax` ([Vue.js][13])\n* Vue Docs: Production Deployment — `https://vuejs.org/guide/best-practices/production-deployment` ([Vue.js][3])\n* Vue Docs: Feature Flags — `https://link.vuejs.org/feature-flags` ([Vue.js][7])\n\nVite documentation (common Vue tooling):\n\n* Vite Docs: Env Variables and Modes (VITE_* exposure + security notes) — `https://vite.dev/guide/env-and-mode` ([vitejs][2])\n* Vite Docs: CLI (`vite preview` not designed for production) — `https://vite.dev/guide/cli` ([vitejs][5])\n* Vite Docs: Server Options (`server.host` can listen on public addresses) — `https://vite.dev/config/server-options` ([vitejs][14])\n\nOWASP and web platform hardening references:\n\n* OWASP Cheat Sheet Series: XSS Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html` ([Vue.js][1])\n* OWASP Cheat Sheet Series: CSRF Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][9])\n* OWASP Cheat Sheet Series: Authorization — `https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][8])\n* OWASP Cheat Sheet Series: HTTP Headers — `https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][4])\n* HTML5 Security Cheat Sheet (referenced by Vue) — `https://html5sec.org/` ([Vue.js][1])\n\nBrowser/platform references:\n\n* MDN: `rel=\"noopener\"` — `https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/noopener` ([MDN Web Docs][12])\n* MDN: Subresource Integrity — `https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity` ([MDN Web Docs][11])\n* web.dev: Trusted Types — `https://web.dev/trusted-types/` ([web.dev][10])\n\n[1]: https://vuejs.org/guide/best-practices/security \"https://vuejs.org/guide/best-practices/security\"\n[2]: https://vite.dev/guide/env-and-mode \"https://vite.dev/guide/env-and-mode\"\n[3]: https://vuejs.org/guide/best-practices/production-deployment \"https://vuejs.org/guide/best-practices/production-deployment\"\n[4]: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html\"\n[5]: https://vite.dev/guide/cli \"https://vite.dev/guide/cli\"\n[6]: https://vite.dev/guide/build \"https://vite.dev/guide/build\"\n[7]: https://vuejs.org/guide/best-practices/production-deployment?utm_source=chatgpt.com \"Production Deployment\"\n[8]: https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html\"\n[9]: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html\"\n[10]: https://web.dev/articles/trusted-types \"https://web.dev/articles/trusted-types\"\n[11]: https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity?utm_source=chatgpt.com \"Subresource Integrity - Security - MDN Web Docs\"\n[12]: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/noopener \"https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/noopener\"\n[13]: https://vuejs.org/guide/essentials/template-syntax \"Template Syntax | Vue.js\"\n[14]: https://vite.dev/config/server-options \"https://vite.dev/config/server-options\"\n","isInternal":false,"tokens":7369,"sizeBytes":31445},{"name":"python-django-web-server-security.md","path":"core/skills/builtin/security-best-practices/references/python-django-web-server-security.md","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/security-best-practices/references/python-django-web-server-security.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Django (Python) Web Security Spec (Django 6.0.x, Python 3.x)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new Django code.\n2. **Security review / vulnerability hunting** in existing Django code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session cookies, `SECRET_KEY`, `SECRET_KEY_FALLBACKS`, database passwords).\n* MUST NOT “fix” security by disabling protections (e.g., removing `CsrfViewMiddleware`, sprinkling `@csrf_exempt`, loosening `ALLOWED_HOSTS` to `['*']`, disabling `SecurityMiddleware`, disabling template auto-escaping, disabling permission checks).\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and concrete configuration values that justify the claim.\n* MUST treat uncertainty honestly: if a protection might exist in infrastructure (reverse proxy, WAF, CDN, ingress controller), report it as “not visible in app code; verify at runtime / edge config”.\n* MUST keep fixes compatible with Django’s intended security model: prefer Django’s built-ins (middleware, auth, forms, ORM) over custom security logic whenever possible. Django’s deployment checklist and system checks are part of the intended model. ([Django Project][1])\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new Django code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default Django APIs and proven libraries over custom security code.\n* MUST avoid introducing new risky sinks (dynamic template rendering from untrusted strings, unsafe redirects, unsafe file serving, shell execution, raw SQL string formatting, SSRF-capable URL fetchers from untrusted input).\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a Django repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. Deployment entrypoints (ASGI/WSGI), Dockerfiles, Procfiles, systemd units, platform manifests.\n2. `settings.py` and environment-specific settings modules.\n3. Middleware ordering and enabled protections.\n4. Authn/authz (login, session management, permissions, admin).\n5. CSRF protections and state-changing endpoints.\n6. Templates and XSS.\n7. File handling (uploads/downloads/static/media) and path traversal.\n8. Injection classes (SQL, command execution, unsafe deserialization).\n9. Outbound requests (SSRF).\n10. Redirect handling (open redirects) + CORS + security headers (CSP, HSTS, etc.).\n11. Dependency/pinning and patch posture.\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nExamples include:\n\n* `request.GET`, `request.POST`, `request.FILES`\n* `request.body`, JSON bodies (e.g., `json.loads(request.body)`), DRF `request.data`\n* URL path parameters (e.g., `<int:id>`, `<slug:...>`)\n* `request.headers` / `request.META` (including `HTTP_HOST`, `HTTP_ORIGIN`, `HTTP_REFERER`, `HTTP_X_FORWARDED_*`)\n* `request.COOKIES`\n* Any data from external systems (webhooks, third-party APIs, message queues)\n* Any persisted content that originated from users (DB rows, cached content, file uploads)\n\nDjango explicitly emphasizes “never trust user-controlled data” and recommends using forms/validation. ([Django Project][2])\n\n### 2.2 State-changing request\n\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook send), or initiate privileged actions.\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + function/class/view name + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common Django misconfigurations. Django provides a “Deployment checklist” and recommends running `manage.py check --deploy` against production settings. ([Django Project][1])\n\n### 3.1 Settings management pattern (SHOULD)\n\n* SHOULD use environment-based configuration (or a secret manager) so production settings are not hard-coded.\n* MUST treat sensitive settings as confidential (e.g., `SECRET_KEY`, DB passwords) and keep them out of source control. Django’s checklist explicitly recommends loading `SECRET_KEY` from env or a file rather than hardcoding. ([Django Project][1])\n* SHOULD separate dev vs prod settings modules, with safe defaults for production (fail closed if critical settings are missing). ([Django Project][1])\n\n### 3.2 Minimum baseline targets (production)\n\n* MUST NOT use `manage.py runserver` as the production entrypoint; use a production-ready WSGI or ASGI server. ([Django Project][1])\n* MUST set `DEBUG = False` in production. ([Django Project][1])\n* MUST set a strong, secret `SECRET_KEY` and keep it secret; MAY use `SECRET_KEY_FALLBACKS` for safe rotation. ([Django Project][1])\n* MUST set `ALLOWED_HOSTS` to expected hosts (no wildcard unless you do your own host validation). ([Django Project][1])\n* MUST enforce HTTPS for authenticated areas (ideally site-wide for any login-capable app) and set `CSRF_COOKIE_SECURE=True` and `SESSION_COOKIE_SECURE=True` when HTTPS is used. ([Django Project][1])\n* SHOULD enable key `SecurityMiddleware` headers/settings: HSTS, Referrer-Policy, COOP, nosniff, SSL redirect (with correct proxy configuration). ([Django Project][3])\n* MUST treat user uploads as untrusted; ensure your web server never interprets them as executable content; keep `MEDIA_ROOT` separate from `STATIC_ROOT`. ([Django Project][1])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### DJANGO-DEPLOY-001: Do not use Django’s development server in production\n\nSeverity: High (if production)\n\nRequired:\n\n* MUST NOT deploy `manage.py runserver` as the production server.\n* MUST run behind a production-grade WSGI or ASGI server. ([Django Project][1])\n\nInsecure patterns:\n\n* Production docs/scripts using `python manage.py runserver 0.0.0.0:8000`.\n* Docker `CMD`/entrypoint uses `runserver`.\n* Kubernetes/Procfile/systemd units invoking `runserver`.\n\nDetection hints:\n\n* Search for `manage.py runserver`, `runserver 0.0.0.0`, `--insecure`.\n* Check Docker `CMD/ENTRYPOINT`, Procfile, systemd unit files, Helm charts.\n\nFix:\n\n* Use a production server (WSGI/ASGI) as recommended in Django’s deployment checklist. ([Django Project][1])\n\nNote:\n\n* `runserver` is fine for local development. Only flag if it’s used as the production entrypoint.\n\n---\n\n### DJANGO-DEPLOY-002: `DEBUG` MUST be disabled in production\n\nSeverity: High\n\nRequired:\n\n* MUST set `DEBUG = False` in production.\n* MUST treat any mechanism that exposes debug pages/tracebacks to untrusted users as a critical information disclosure risk. Django’s checklist explicitly warns `DEBUG=True` leaks source excerpts, local variables, settings, and more. ([Django Project][1])\n\nInsecure patterns:\n\n* `DEBUG = True` in production settings.\n* Environment defaults to `DEBUG=True` unless explicitly overridden.\n\nDetection hints:\n\n* Search `DEBUG = True`, `DEBUG=os.environ.get(..., True)`, `DJANGO_DEBUG`, `.env` files.\n* Look for “production” settings modules that import from dev defaults.\n\nFix:\n\n* Set `DEBUG=False` in prod settings; use explicit environment config.\n* Ensure error reporting is via safe logging/monitoring, not debug pages. ([Django Project][1])\n\n---\n\n### DJANGO-CONFIG-001: `SECRET_KEY` must be strong, secret, and rotated safely\n\nSeverity: High (Critical if missing in production with signing/sessions)\n\nRequired:\n\n* MUST set a large random `SECRET_KEY` in production and keep it secret. ([Django Project][1])\n* MUST NOT commit it to source control or print/log it. ([Django Project][1])\n* SHOULD load it from env or a file/secret store (not hard-coded). ([Django Project][1])\n* MAY rotate keys using `SECRET_KEY_FALLBACKS` to avoid instantly invalidating all signed data; MUST remove old keys from fallbacks in a timely manner. ([Django Project][1])\n\nInsecure patterns:\n\n* Hard-coded `SECRET_KEY = \"...\"` in repo for production.\n* `SECRET_KEY` reused across environments.\n* `SECRET_KEY_FALLBACKS` contains long-expired keys indefinitely.\n\nDetection hints:\n\n* Search for `SECRET_KEY =`, `SECRET_KEY_FALLBACKS`, `.env` committed files, `print(settings.SECRET_KEY)`.\n\nFix:\n\n* Load from secret manager / environment variable.\n* If rotating:\n\n  * Set new `SECRET_KEY`\n  * Keep old key(s) temporarily in `SECRET_KEY_FALLBACKS`\n  * Remove old key(s) after the rotation window. ([Django Project][1])\n\n---\n\n### DJANGO-HOST-001: Host header must be validated (`ALLOWED_HOSTS` must be strict)\n\nSeverity: Medium\n\nRequired:\n\n* MUST set `ALLOWED_HOSTS` in production to your expected domains/hosts. ([Django Project][1])\n* MUST NOT set `ALLOWED_HOSTS = ['*']` in production unless you also implement your own robust `Host` validation (Django warns that wildcards require your own validation to avoid CSRF-class attacks). ([Django Project][1])\n* SHOULD configure the fronting web server to reject unknown hosts early (defense-in-depth). ([Django Project][1])\n\nInsecure patterns:\n\n* `ALLOWED_HOSTS = ['*']` (or env expands to `*`) in production.\n* `ALLOWED_HOSTS = []` with `DEBUG=False` (site won’t run, or misconfigured deployments attempt workarounds).\n\nDetection hints:\n\n* Search `ALLOWED_HOSTS`.\n* Check platform environment settings that override `ALLOWED_HOSTS`.\n\nFix:\n\n* Set `ALLOWED_HOSTS = ['example.com', 'www.example.com', ...]` for prod.\n* Keep dev hosts separate.\n\nNotes:\n\n* Django uses the Host header for URL construction; fake Host values can lead to CSRF, cache poisoning, and poisoned email links (Django security docs call this out). ([Django Project][2])\n\n---\n\n### DJANGO-HTTPS-001: If TLS is used cookie transport must be secured\n\nSeverity: High (Critical for auth-enabled apps)\n\nNOTE: Only enforce this if TLS is enabled, as it will break non-TLS applications\n\nIf using TLS:\n* MUST set:\n\n  * `CSRF_COOKIE_SECURE = True` ([Django Project][1])\n  * `SESSION_COOKIE_SECURE = True` ([Django Project][1])\n* SHOULD consider enabling:\n\n  * `SECURE_SSL_REDIRECT = True` (with correct proxy config) ([Django Project][3])\n  * HSTS via `SECURE_HSTS_SECONDS` (+ includeSubDomains/preload as appropriate). ([Django Project][3])\n\nInsecure patterns:\n\n* Login pages over HTTP, or mixed HTTP/HTTPS with the same session cookie.\n* `CSRF_COOKIE_SECURE=False` or `SESSION_COOKIE_SECURE=False` in production HTTPS.\n* HSTS enabled incorrectly (can break site for the duration).\n\nDetection hints:\n\n* Inspect `settings.py` for `CSRF_COOKIE_SECURE`, `SESSION_COOKIE_SECURE`, `SECURE_SSL_REDIRECT`, `SECURE_HSTS_SECONDS`.\n* Inspect proxy/ingress config for HTTP->HTTPS redirect behavior.\n\nFix:\n\n* Enable HTTPS redirect and secure cookies.\n* Add HSTS carefully (start with low value, validate, then increase). Django warns misconfig can break your site for the HSTS duration. ([Django Project][3])\n\n---\n\n### DJANGO-PROXY-001: Reverse proxy trust must be configured correctly (`SECURE_PROXY_SSL_HEADER`)\n\nSeverity: Medium (when behind a TLS proxy)\n\nRequired:\n\n* If behind a reverse proxy that terminates TLS, MUST configure Django so `request.is_secure()` reflects the *external* scheme, otherwise CSRF and other logic can break. Django documents using `SECURE_PROXY_SSL_HEADER` for this. ([Django Project][3])\n* MUST only set `SECURE_PROXY_SSL_HEADER` if you control the proxy (or have guarantees) and it strips inbound spoofed headers. Django explicitly warns misconfig can compromise security and lists required conditions. ([Django Project][3])\n\nInsecure patterns:\n\n* `SECURE_PROXY_SSL_HEADER = (\"HTTP_X_FORWARDED_PROTO\", \"https\")` in an environment where the proxy does not strip user-supplied `X-Forwarded-Proto`.\n* Infinite redirect loops after setting `SECURE_SSL_REDIRECT=True` (often indicates proxy HTTPS detection is wrong). ([Django Project][3])\n\nDetection hints:\n\n* Search `SECURE_PROXY_SSL_HEADER`, `SECURE_SSL_REDIRECT`.\n* Inspect ingress/proxy behavior for stripping forwarded headers.\n\nFix:\n\n* Set `SECURE_PROXY_SSL_HEADER` only if the proxy strips and sets the header correctly (per Django’s documented prerequisites). ([Django Project][3])\n\n---\n\n### DJANGO-SESS-001: Session cookies must use secure attributes in production\n\nSeverity: Medium (Only if TLS enabled)\n\nRequired (production, HTTPS):\n\n* MUST set `SESSION_COOKIE_SECURE=True` (only transmit over HTTPS). ([Django Project][3])\n* MUST keep `SESSION_COOKIE_HTTPONLY=True` (Django default is `True`). ([Django Project][3])\n* SHOULD keep `SESSION_COOKIE_SAMESITE='Lax'` (Django default is `Lax`) unless a justified cross-site flow requires `None`. ([Django Project][3])\n* SHOULD avoid setting `SESSION_COOKIE_DOMAIN` unless you truly need cross-subdomain cookies (subdomain-wide cookies expand attack surface).\n\nInsecure patterns:\n\n* `SESSION_COOKIE_SECURE=False` in production HTTPS.\n\nIMPORTANT NOTE: Only set `Secure` in production environment when TLS is configured. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n\n* `SESSION_COOKIE_HTTPONLY=False`.\n* `SESSION_COOKIE_SAMESITE=None` combined with cookie-authenticated state-changing endpoints (higher CSRF risk).\n\nDetection hints:\n\n* Search for `SESSION_COOKIE_` settings, `response.set_cookie(..., httponly=..., secure=..., samesite=...)`.\n\nFix:\n\n* Set the above explicitly in production settings.\n* Validate compatibility with your auth flows. ([Django Project][3])\n\n---\n\n### DJANGO-SESS-002: CSRF cookie settings must be deliberate (HttpOnly has tradeoffs)\n\nSeverity: Medium\n\nRequired:\n\n* SHOULD set `CSRF_COOKIE_SECURE=True` when using HTTPS/TLS. ([Django Project][3])\n* SHOULD keep `CSRF_COOKIE_SAMESITE='Lax'` unless you have a cross-site requirement. Django default is `Lax`. ([Django Project][3])\n* MAY set `CSRF_COOKIE_HTTPONLY=True` (default is `False`) if your frontend does not need to read the CSRF cookie. If you enable it, your JS must read the CSRF token from the DOM instead (Django documents this). ([Django Project][3])\n\nInsecure patterns:\n\n* `CSRF_COOKIE_SECURE=False` in production HTTPS/TLS.\n* Setting `CSRF_COOKIE_HTTPONLY=True` but still relying on “read csrftoken cookie in JS” patterns (breaks CSRF for AJAX).\n* `CSRF_COOKIE_SAMESITE=None` without a clear reason.\n\nDetection hints:\n\n* Search for `CSRF_COOKIE_` settings.\n* Search JS for `document.cookie` usage to fetch `csrftoken`.\n\nFix:\n\n* Align cookie settings with your CSRF token acquisition method (cookie vs DOM) as Django describes. ([Django Project][4])\n\n---\n\n### DJANGO-CSRF-001: Cookie-authenticated state-changing requests MUST be CSRF-protected\n\nSeverity: High\n\nRequired:\n\n* MUST keep `django.middleware.csrf.CsrfViewMiddleware` enabled (it is activated by default). ([Django Project][4])\n* MUST include `{% csrf_token %}` in internal POST forms; MUST NOT include it in forms that POST to external URLs (Django warns this leaks the token). ([Django Project][4])\n* MUST protect all state-changing endpoints (POST/PUT/PATCH/DELETE) that rely on cookies for authentication.\n* For AJAX/SPA calls, MUST send the CSRF token via the `X-CSRFToken` header (or configured header name) as documented. ([Django Project][4])\n* MUST be very careful with `@csrf_exempt` and use it only when absolutely necessary; if used, MUST replace CSRF with an appropriate alternative control (e.g., request signing for webhooks). Django explicitly warns about `csrf_exempt`. ([Django Project][2])\n\nInsecure patterns:\n\n* Missing `CsrfViewMiddleware` in `MIDDLEWARE`.\n* `@csrf_exempt` on general-purpose authenticated views.\n* POST/PUT/PATCH/DELETE endpoints with session auth and no CSRF tokens.\n* Using GET for state-changing actions (amplifies CSRF risk).\n\nDetection hints:\n\n* Inspect `settings.py` `MIDDLEWARE` for `CsrfViewMiddleware` and its order (Django notes it should come before middleware that assumes CSRF is handled). ([Django Project][4])\n* Search for `csrf_exempt`, `csrf_protect`, `ensure_csrf_cookie`.\n* Enumerate URL patterns for non-GET methods; confirm CSRF coverage.\n\nFix:\n\n* Re-enable `CsrfViewMiddleware`, add CSRF tokens to forms, and add AJAX header handling.\n* For caching decorators: if you cache a view that needs CSRF tokens, apply `@csrf_protect` as Django documents to avoid caching a response without CSRF cookie/Vary headers. ([Django Project][4])\n\nNotes:\n\n* When deployed with HTTPS, Django’s CSRF middleware also checks the Referer header for same-origin (Django security docs mention this). ([Django Project][2])\n\n---\n\n### DJANGO-XSS-001: Prevent reflected/stored XSS in templates and HTML generation\n\nSeverity: High\n\nRequired:\n\n* MUST rely on Django template auto-escaping (safe-by-default) for HTML templates. Django security docs highlight that Django templates escape dangerous characters but have limitations. ([Django Project][2])\n* MUST NOT disable auto-escaping broadly (`{% autoescape off %}`) unless the content is trusted or safely sanitized. ([Django Project][5])\n* MUST NOT mark untrusted content as safe:\n\n  * Avoid `mark_safe(...)` on user data.\n  * Avoid `|safe` on user-controlled content.\n* MUST be careful about HTML context pitfalls (e.g., unquoted attributes); Django explicitly shows an example where escaping does not protect an unquoted attribute context. ([Django Project][2])\n* SHOULD prefer safe HTML construction helpers (e.g., `format_html`) rather than manual concatenation that risks missing escapes. ([Django Project][6])\n\nInsecure patterns:\n\n* `{% autoescape off %}{{ user_input }}{% endautoescape %}`\n* `{{ user_input|safe }}`\n* `mark_safe(request.GET[\"q\"])`\n* Unquoted attribute injections: `<style class={{ var }}>...` (Django’s own example). ([Django Project][2])\n\nDetection hints:\n\n* Search templates for `|safe`, `autoescape off`, `safeseq`.\n* Search Python for `mark_safe`, `SafeString`, or direct HTML concatenation with request/DB values.\n* Review any code returning `HttpResponse(user_value)` where `user_value` contains HTML.\n\nFix:\n\n* Remove unsafe marking; sanitize only when strictly necessary (use an allowlist-based HTML sanitizer).\n* Quote attributes and avoid placing untrusted values into dangerous contexts.\n* Add CSP as defense-in-depth (see DJANGO-CSP-001). ([Django Project][2])\n\n---\n\n### DJANGO-TEMPLATE-001: Never render untrusted template source strings\n\nSeverity: High to Critical (depends on context and exposure)\n\nRequired:\n\n* MUST NOT render templates where the template source string is influenced by untrusted input (request, user content, DB rows editable by untrusted users).\n* MUST treat “template from string” patterns as dangerous, even if Django templates are more constrained than some other engines: they can still leak data from context, bypass escaping, and create XSS or content injection.\n\nInsecure patterns:\n\n* `Template(request.GET[\"tmpl\"]).render(Context(...))`\n* Saving user templates in the DB and rendering them with normal privileges/context.\n\nDetection hints:\n\n* Search for `django.template.Template(`, `Engine.from_string`, `.render(Context(` with non-constant strings.\n* Trace where the template string comes from (admin panels, DB, uploads, requests).\n\nFix:\n\n* Replace with non-executing formatting (e.g., `string.Template`, explicit placeholders) or a strict allowlisted rendering model.\n* If you *must* support user-defined templates, isolate heavily (separate service/tenant context, strict allowlists, and assume bypasses are possible).\n\n---\n\n### DJANGO-SQL-001: Prevent SQL injection (use ORM or parameterized raw SQL)\n\nSeverity: High\n\nRequired:\n\n* MUST use Django ORM/querysets for normal DB access; Django notes querysets are parameterized and protected from SQL injection under typical use. ([Django Project][2])\n* MUST be very careful with raw SQL; if using `raw()`, `cursor.execute()`, `extra()`, or `RawSQL`, MUST pass parameters separately (e.g., `params=`) and MUST NOT string-interpolate untrusted input into SQL. Django’s raw SQL docs warn to escape user-controlled parameters using `params`. ([Django Project][7])\n* MUST NOT quote placeholders in SQL templates (Django docs explicitly warn that quoting `%s` placeholders makes it unsafe). ([Django Project][8])\n* SHOULD avoid `extra()` and `RawSQL` unless necessary; Django security docs call for caution. ([Django Project][2])\n\nInsecure patterns:\n\n* `cursor.execute(f\"SELECT ... WHERE id={request.GET['id']}\")`\n* `Model.objects.raw(\"... %s\" % user_input)` (string formatting)\n* `extra(where=[f\"headline='{q}'\"])`\n* Quoted placeholders: `WHERE othercol = '%s'` (explicitly documented as unsafe). ([Django Project][8])\n\nDetection hints:\n\n* Grep for `.raw(`, `.extra(`, `RawSQL(`, `connection.cursor()`, `.execute(`.\n* Grep for SQL keywords (`SELECT`, `UPDATE`, `DELETE`, `INSERT`) in Python strings.\n* Track untrusted inputs into these call sites.\n\nFix:\n\n* Prefer ORM queries.\n* If raw SQL is unavoidable, use parameters (`params`, DB-API param binding) and do not quote placeholders. ([Django Project][7])\n\n---\n\n### DJANGO-CMD-001: Prevent OS command injection\n\nSeverity: Critical to High (depends on exposure)\n\nRequired:\n\n* MUST avoid executing system commands with attacker-influenced input.\n* If subprocess is necessary:\n\n  * MUST pass args as a list (not a shell string).\n  * MUST NOT use `shell=True` with attacker-influenced content.\n  * SHOULD use strict allowlists for variable components.\n* SHOULD prefer pure-Python libraries instead of shelling out.\n\nInsecure patterns:\n\n* `os.system(request.GET[\"cmd\"])`\n* `subprocess.run(f\"convert {path}\", shell=True)` where `path` is user-controlled.\n\nDetection hints:\n\n* Search `os.system`, `subprocess`, `Popen`, `shell=True`.\n* Trace request/DB inputs into those calls.\n\nFix:\n\n* Replace with library APIs; if unavoidable, hard-code executable and allowlist validated parameters.\n\n---\n\n### DJANGO-UPLOAD-001: File uploads must be validated, stored safely, and served safely\n\nSeverity: High\n\nRequired:\n\n* MUST treat all user uploads as untrusted. Django explicitly warns “Media files are uploaded by your users. They’re untrusted!” ([Django Project][1])\n* MUST ensure the web server never interprets user uploads as executable code (e.g., don’t allow uploaded `.php` or HTML to execute/inline as active content). ([Django Project][1])\n* MUST enforce size limits (at least at the web server; Django security docs recommend limiting upload size at the server to prevent DoS). ([Django Project][2])\n* SHOULD validate file types using allowlists and content checks (not only extensions).\n* SHOULD store uploads outside the application code directory and outside any static root.\n* SHOULD consider serving uploads from a separate top-level/second-level domain to reduce same-origin impact; Django security docs recommend a distinct domain and note that a subdomain may be insufficient for some protections. ([Django Project][2])\n* MUST be aware of polyglot upload risks: Django documents a case where HTML can be uploaded “as an image” by using a valid PNG header (and may be served as HTML depending on the web server). ([Django Project][2])\n\nInsecure patterns:\n\n* Serving uploads inline with `text/html` or without forcing download for potentially active formats.\n* Upload allowlist based only on extension.\n* Upload storage inside static roots or code roots.\n\nDetection hints:\n\n* Search for `request.FILES`, `FileField`, `ImageField`, upload forms/views.\n* Inspect upload serving paths and Nginx/Apache config (media handlers).\n* Check `MEDIA_URL`, `MEDIA_ROOT`, and static config.\n\nFix:\n\n* Configure the web server to serve uploads as inert bytes (no execution), and consider forcing `Content-Disposition: attachment` for risky types.\n* Use a separate domain for user content when warranted. ([Django Project][2])\n\n---\n\n### DJANGO-PATH-001: Prevent path traversal and unsafe file serving (static/media separation)\n\nSeverity: High\n\nRequired:\n\n* MUST NOT treat user input as a filesystem path for reads/writes/serving.\n* MUST keep `MEDIA_ROOT` and `STATIC_ROOT` distinct; Django settings docs explicitly warn they must have different values to avoid security implications. ([Django Project][3])\n* SHOULD prefer using Django storage APIs keyed by server-side identifiers rather than accepting arbitrary relative paths from users.\n\nInsecure patterns:\n\n* `open(os.path.join(MEDIA_ROOT, request.GET[\"path\"]))`\n* Download endpoints that take `?file=../../...` style parameters.\n* Misconfigured `MEDIA_ROOT == STATIC_ROOT`.\n\nDetection hints:\n\n* Grep for `open(`, `Path(`, `os.path.join(` used with request values.\n* Check `MEDIA_ROOT`, `STATIC_ROOT` in settings. ([Django Project][3])\n\nFix:\n\n* Use server-side IDs mapped to known files.\n* Keep static and media separated and ensure the web server treats media as untrusted. ([Django Project][3])\n\n---\n\n### DJANGO-REDIRECT-001: Prevent open redirects (`next`, `return_to`, `redirect`)\n\nSeverity: Medium (High when combined with auth flows)\n\nRequired:\n\n* MUST validate redirect targets derived from untrusted input (e.g., `next`, `return_to`).\n* SHOULD restrict to same-site relative paths or allowlisted hosts/schemes.\n* SHOULD use Django’s safe URL helpers (e.g., `django.utils.http.url_has_allowed_host_and_scheme`) rather than custom parsing.\n\nInsecure patterns:\n\n* `return redirect(request.GET.get(\"next\"))` with no validation.\n* Redirect allowlist implemented with naive string checks.\n\nDetection hints:\n\n* Search for `redirect(` and track origin of the target.\n* Search for parameters named `next`, `return_to`, `redirect`, `url`.\n\nFix:\n\n* Validate with allowlists and default to a safe internal path if validation fails.\n* Ensure host validation via `ALLOWED_HOSTS` remains strict (see DJANGO-HOST-001). ([Django Project][3])\n\n---\n\n### DJANGO-HEADERS-001: Enable essential security headers (SecurityMiddleware + clickjacking protection)\n\nSeverity: Medium to High\n\nRequired:\n\n* SHOULD use `django.middleware.security.SecurityMiddleware` and configure it appropriately (production) for:\n\n  * `X-Content-Type-Options: nosniff` (Django setting `SECURE_CONTENT_TYPE_NOSNIFF`, default `True`). ([Django Project][3])\n  * `Referrer-Policy` (Django setting `SECURE_REFERRER_POLICY`, default `'same-origin'`). ([Django Project][3])\n  * COOP (Django setting `SECURE_CROSS_ORIGIN_OPENER_POLICY`, default `'same-origin'`). ([Django Project][3])\n  * HTTPS redirects and HSTS as appropriate (see DJANGO-HTTPS-001). ([Django Project][3])\n* SHOULD enable clickjacking protection via X-Frame-Options middleware; Django security docs strongly recommend it for sites that don’t need third-party framing. ([Django Project][2])\n\nInsecure patterns:\n\n* Missing SecurityMiddleware.\n* Missing clickjacking protection (or disabling it globally) without a clear framing requirement.\n* Over-broad framing allowances for sensitive endpoints.\n\nDetection hints:\n\n* Inspect `MIDDLEWARE` for SecurityMiddleware and XFrameOptionsMiddleware.\n* Search for per-view disabling of framing/CSRF protections.\n\nFix:\n\n* Add/enable middleware and configure the settings intentionally. ([Django Project][3])\n\nNOTE:\n\n* Some headers may be set at the edge (CDN/reverse proxy). If not visible in app code, flag as “verify at edge”.\n\n---\n\n### DJANGO-CSP-001: Deploy a Content Security Policy (CSP) as defense-in-depth\n\nSeverity: Medium (High for apps rendering untrusted content)\n\nNOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n\nRequired:\n\n* SHOULD deploy a CSP to mitigate XSS and content injection classes; Django’s security docs recommend CSP and note it is new in Django 6.0. ([Django Project][2])\n* MUST understand CSP limitations:\n\n  * Avoid excluding routes from CSP coverage; Django warns that an unprotected page can undermine protected pages due to same-origin policy. ([Django Project][2])\n* MAY start with `SECURE_CSP_REPORT_ONLY` to iterate safely (Django provides report-only support). ([Django Project][3])\n\nInsecure patterns:\n\n* No CSP on apps that render user-controlled content.\n* CSP excludes “just a couple pages” (weakens overall protection), especially pages with any injection surface. ([Django Project][2])\n* CSP uses overly permissive directives (e.g., widespread `unsafe-inline`) without justification.\n\nDetection hints:\n\n* Search `SECURE_CSP`, `SECURE_CSP_REPORT_ONLY`, and CSP middleware configuration.\n* Inspect reverse proxy/CDN config for CSP headers.\n\nFix:\n\n* Implement a realistic CSP, ideally report-only first, then enforce. ([Django Project][3])\n\n---\n\n### DJANGO-AUTH-001: Password storage must use Django’s secure hashers; password policy must be configured\n\nSeverity: High\n\nRequired:\n\n* MUST use Django’s built-in password hashing (never store plaintext or reversible encrypted passwords).\n* SHOULD prefer modern hashers and keep defaults updated; Django documents `PASSWORD_HASHERS` and includes modern options (Argon2, bcrypt, scrypt, PBKDF2 variants). ([Django Project][3])\n* SHOULD configure `AUTH_PASSWORD_VALIDATORS` (default is empty) for production password policy. ([Django Project][3])\n\nInsecure patterns:\n\n* Custom password storage or hashing.\n* Plaintext passwords stored in DB fields.\n* No password validation on consumer-facing apps.\n\nDetection hints:\n\n* Search for `.set_password(` usage vs manual hashing.\n* Inspect settings for `PASSWORD_HASHERS` and `AUTH_PASSWORD_VALIDATORS`. ([Django Project][3])\n\nFix:\n\n* Use Django auth user model APIs.\n* Enable password validators appropriate to the product’s risk profile. ([Django Project][3])\n\n---\n\n### DJANGO-AUTHZ-001: Authorization must be explicit and consistent\n\nSeverity: High\n\nRequired:\n\n* MUST enforce authorization checks on every privileged action (view, modify, admin-like operations).\n* MUST NOT rely on UI-only restrictions (e.g., hiding buttons) without server-side permission checks.\n* SHOULD use Django’s permissions/groups and per-object authorization patterns where applicable.\n\nInsecure patterns:\n\n* Views that assume “user is logged in” implies “user may do action”.\n* Missing authorization checks on update/delete endpoints.\n\nDetection hints:\n\n* Enumerate views that modify state; ensure they validate ownership/permission.\n* Look for use of only `is_authenticated` or only `is_staff` without checking object-level access.\n\nFix:\n\n* Add explicit permission checks and tests for unauthorized access.\n\n---\n\n### DJANGO-ADMIN-001: Django admin must be treated as a high-value target\n\nSeverity: High\n\nRequired:\n\n* MUST ensure admin is protected by strong authentication and HTTPS-only transport (see DJANGO-HTTPS-001). ([Django Project][1])\n* SHOULD restrict admin exposure (network allowlists, VPN, SSO, or additional authentication controls) when possible.\n* SHOULD audit installed admin extensions and third-party apps for XSS/CSRF exposure.\n\nInsecure patterns:\n\n* Admin exposed to the internet with weak authentication.\n* Admin served over HTTP.\n\nDetection hints:\n\n* Search `urlpatterns` for `admin.site.urls`.\n* Check deployment config for IP allowlisting or auth gateways.\n\nFix:\n\n* Add network controls and enforce HTTPS.\n\n---\n\n### DJANGO-LOG-001: Logging and error reporting must not leak secrets\n\nSeverity: Medium to High\n\nRequired:\n\n* MUST NOT log secrets (including `SECRET_KEY`, session cookies, auth headers, password reset tokens).\n* MUST configure production logging deliberately; Django’s deployment checklist explicitly calls out reviewing logging before production. ([Django Project][1])\n* MUST ensure `DEBUG=False` in production so exceptions aren’t rendered with sensitive context. ([Django Project][1])\n\nInsecure patterns:\n\n* Logging full request headers or cookies in production.\n* Printing settings dictionaries.\n* Debug error pages.\n\nDetection hints:\n\n* Inspect `LOGGING` config; search for middleware that logs request headers/cookies.\n* Grep for `print(settings` / `logging.info(request.META)` patterns.\n\nFix:\n\n* Redact sensitive values; log IDs not secrets.\n* Use structured logging and a safe error monitoring tool. ([Django Project][1])\n\n---\n\n### DJANGO-SUPPLY-001: Dependency and patch hygiene (Django + security-critical deps)\n\nSeverity: Medium (High if known vulnerable versions)\n\nRequired:\n\n* SHOULD pin and regularly update Django and security-critical dependencies.\n* MUST respond to Django security releases promptly.\n\nDetection hints:\n\n* Check `requirements.txt`, lockfiles, build images.\n* Identify Django version; compare against latest supported release (Django’s download page publishes current stable and supported branches). ([Django Project][9])\n\nFix:\n\n* Upgrade to patched versions; add regression tests for previously vulnerable classes.\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* Deployment/dev server:\n\n  * `manage.py runserver`, `runserver 0.0.0.0`, `--insecure` ([Django Project][1])\n* Debug / settings:\n\n  * `DEBUG = True` ([Django Project][1])\n  * `SECRET_KEY =`, `SECRET_KEY_FALLBACKS` ([Django Project][1])\n* Host validation:\n\n  * `ALLOWED_HOSTS = ['*']` ([Django Project][3])\n* HTTPS and proxy:\n\n  * `SECURE_SSL_REDIRECT`, `SECURE_HSTS_SECONDS`, `SECURE_PROXY_SSL_HEADER` ([Django Project][3])\n* Cookies / sessions:\n\n  * `SESSION_COOKIE_SECURE`, `SESSION_COOKIE_HTTPONLY`, `SESSION_COOKIE_SAMESITE` ([Django Project][3])\n  * `CSRF_COOKIE_SECURE`, `CSRF_COOKIE_HTTPONLY`, `CSRF_COOKIE_SAMESITE` ([Django Project][3])\n* CSRF bypasses:\n\n  * `csrf_exempt`, missing `CsrfViewMiddleware`, POST forms without `{% csrf_token %}` ([Django Project][4])\n* XSS:\n\n  * `|safe`, `autoescape off`, `mark_safe(`, HTML string concatenation ([Django Project][5])\n* SQL injection:\n\n  * `.raw(`, `.extra(`, `RawSQL(`, `cursor.execute(` with formatted SQL strings ([Django Project][7])\n* User uploads / media:\n\n  * `request.FILES`, `MEDIA_ROOT`, `MEDIA_URL`, serving media inline; `MEDIA_ROOT == STATIC_ROOT` ([Django Project][1])\n* Redirects:\n\n  * `redirect(request.GET.get(\"next\"))` patterns; missing allowlist validation\n* Security headers and CSP:\n\n  * Missing `SecurityMiddleware`, missing X-Frame-Options protection, missing `SECURE_CSP` adoption (where appropriate) ([Django Project][2])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (template/SQL/subprocess/files/redirect/http)\n* protective controls present (middleware, validation, allowlists, authz checks)\n* whether security headers/controls are set in-app vs at the edge\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary Django documentation:\n\n```text\n- Django Downloads (current stable & supported branches): https://www.djangoproject.com/download/\n- Django 6.0 Release Notes: https://docs.djangoproject.com/en/6.0/releases/6.0/\n- Django: Deployment checklist (incl. check --deploy, runserver warning, HTTPS/cookies guidance): https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/\n- Django: Settings reference (SecurityMiddleware settings, cookies, SECRET_KEY_FALLBACKS, CSP settings): https://docs.djangoproject.com/en/6.0/ref/settings/\n- Django: Security in Django (XSS/CSRF/SQLi/clickjacking/HTTPS/host header validation/uploads/CSP): https://docs.djangoproject.com/en/6.0/topics/security/\n- Django: CSRF how-to (middleware, csrf_token usage, AJAX header patterns, csrf_exempt cautions): https://docs.djangoproject.com/en/6.0/howto/csrf/\n- Django: Performing raw SQL queries (parameterization guidance): https://docs.djangoproject.com/en/6.0/topics/db/sql/\n- Django: QuerySet API reference (extra() cautions; “do not quote placeholders” guidance): https://docs.djangoproject.com/en/6.0/ref/models/querysets/\n- Django: Template built-ins (autoescape tag): https://docs.djangoproject.com/en/6.0/ref/templates/builtins/\n- Django: Template language reference (turning off autoescape & risks): https://docs.djangoproject.com/en/6.0/ref/templates/language/\n- Django: Utilities reference (e.g., format_html): https://docs.djangoproject.com/en/6.0/ref/utils/\n```\n\nOWASP:\n\n```text\n- OWASP Cheat Sheet Series: Django Security Cheat Sheet: https://cheatsheetseries.owasp.org/cheatsheets/Django_Security_Cheat_Sheet.html\n```\n\n[1]: https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/ \"https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/\"\n[2]: https://docs.djangoproject.com/en/6.0/topics/security/ \"Security in Django | Django documentation | Django\"\n[3]: https://docs.djangoproject.com/en/6.0/ref/settings/ \"Settings | Django documentation | Django\"\n[4]: https://docs.djangoproject.com/en/6.0/howto/csrf/ \"How to use Django’s CSRF protection | Django documentation | Django\"\n[5]: https://docs.djangoproject.com/en/6.0/ref/templates/builtins/ \"https://docs.djangoproject.com/en/6.0/ref/templates/builtins/\"\n[6]: https://docs.djangoproject.com/en/6.0/ref/utils/ \"https://docs.djangoproject.com/en/6.0/ref/utils/\"\n[7]: https://docs.djangoproject.com/en/6.0/topics/db/sql/ \"https://docs.djangoproject.com/en/6.0/topics/db/sql/\"\n[8]: https://docs.djangoproject.com/en/6.0/ref/models/querysets/ \"https://docs.djangoproject.com/en/6.0/ref/models/querysets/\"\n[9]: https://www.djangoproject.com/download/ \"Download Django | Django\"\n","isInternal":false,"tokens":8837,"sizeBytes":38660},{"name":"python-fastapi-web-server-security.md","path":"core/skills/builtin/security-best-practices/references/python-fastapi-web-server-security.md","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/security-best-practices/references/python-fastapi-web-server-security.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# FastAPI (Python) Web Security Spec (FastAPI 0.128.x, Python 3.x) ([PyPI][1])\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new FastAPI code.\n2. **Security review / vulnerability hunting** in existing FastAPI code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\nFastAPI is commonly deployed with an ASGI server (e.g., Uvicorn) and is built on Starlette + Pydantic, so this spec covers those layers where they affect security. ([PyPI][1])\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session cookies, signing keys, database URLs with credentials).\n* MUST NOT “fix” security by disabling protections (e.g., weakening auth, making CORS permissive, skipping signature checks, disabling validation, turning off TLS verification, adding `allow_origins=[\"*\"]` with credentials).\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and configuration values that justify the claim.\n* MUST treat uncertainty honestly: if a protection might exist in infrastructure (reverse proxy, WAF, CDN, service mesh), report it as “not visible in app code; verify at runtime/config”.\n* MUST treat browser controls correctly:\n\n  * CORS is **not** an auth mechanism; it only affects browsers.\n  * CSRF defenses apply when the browser automatically attaches credentials (cookies); they are usually not relevant for purely header-token APIs. ([OWASP Cheat Sheet Series][2])\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new FastAPI code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default APIs and proven libraries over custom security code.\n* MUST avoid introducing new risky sinks (shell execution, unsafe deserialization, dynamic eval, untrusted template rendering, unsafe file serving, unsafe redirects, arbitrary outbound fetching).\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a FastAPI repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. App entrypoints / deployment scripts / Dockerfiles / Procfiles / Helm/terraform.\n2. ASGI server configuration (Uvicorn/Gunicorn), proxy settings, debug/reload settings.\n3. FastAPI app configuration (docs exposure, middleware, trusted hosts, CORS).\n4. Authn/Authz design (dependencies, JWT/session handling, password storage).\n5. Cookie/session usage + CSRF (if cookies are used).\n6. Input validation and output shaping (Pydantic models, mass assignment, excessive data exposure).\n7. Template rendering and XSS/SSTI (if HTML is served).\n8. File handling (uploads + downloads), StaticFiles, Range support.\n9. Injection classes (SQL, command execution, unsafe deserialization).\n10. Outbound requests (SSRF), redirect handling, WebSockets security.\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nExamples include:\n\n* Query parameters / path parameters\n* JSON bodies (including nested fields)\n* Headers (including `Host`, `Origin`, `X-Forwarded-*`)\n* Cookies (including session cookies)\n* File uploads (multipart parts)\n* WebSocket messages, query params, and headers during handshake ([Starlette][3])\n* Any data from external systems (webhooks, third-party APIs, message queues)\n* Any persisted user content (DB rows) that originated from users\n\n### 2.2 State-changing request\n\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook send), or initiate privileged actions.\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + function/route name + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common FastAPI/ASGI misconfigurations.\n\nBaseline goals:\n\n* No debug tracebacks or auto-reload in production. ([PyPI][4])\n* Run under a production ASGI server configuration (workers, timeouts, resource controls). ([PyPI][4])\n* Host header validation enabled (TrustedHostMiddleware or equivalent). ([PyPI][5])\n* CORS disabled unless explicitly needed; if enabled, it is strict and least-privilege. ([OWASP Cheat Sheet Series][6])\n* Auth is enforced consistently via dependencies (no “oops, forgot auth on this route”). ([FastAPI][7])\n* If cookies/sessions are used, cookie flags are secure and CSRF is addressed. ([OWASP Cheat Sheet Series][8])\n* Request size limits and multipart limits exist at the edge and are validated in app as needed (to mitigate memory/CPU DoS). ([advisories.gitlab.com][9])\n* Dependencies are patched promptly, especially Starlette/python-multipart (multiple DoS and traversal advisories exist historically). ([advisories.gitlab.com][10])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### FASTAPI-DEPLOY-001: Do not use auto-reload / dev-only server modes in production\n\nSeverity: High (if production)\n\nRequired:\n\n* MUST NOT run production using auto-reload/watch mode (e.g., Uvicorn reload).\n* MUST run with a production process model (e.g., multiple workers where appropriate) and stable server settings. ([PyPI][4])\n\nInsecure patterns:\n\n* `uvicorn ... --reload` (or equivalent “reload=True” configs) in production entrypoints.\n* Docker/Procfile/systemd commands that run with `--reload` in production.\n\nDetection hints:\n\n* Search for `--reload`, `reload=True`, `watchfiles`, `fastapi dev`, “development” run scripts.\n* Check Docker CMD/ENTRYPOINT, Procfile, systemd units, shell scripts.\n\nFix:\n\n* Remove reload in production; run Uvicorn/Gunicorn with stable settings and explicit worker configuration. ([PyPI][4])\n\nNote:\n\n* Reload is fine for local development. Only flag when it is clearly used as a production entrypoint.\n\n---\n\n### FASTAPI-DEPLOY-002: Debug mode MUST be disabled in production\n\nSeverity: Critical\n\nRequired:\n\n* MUST NOT enable debug tracebacks in production (FastAPI/Starlette debug mode can expose sensitive internals and make some exploit chains easier). ([PyPI][5])\n* MUST treat any configuration that returns detailed stack traces to clients as sensitive.\n\nInsecure patterns:\n\n* `app = FastAPI(debug=True)` (or Starlette `debug=True`), or equivalent environment toggles enabling debug in production. ([PyPI][5])\n* Server/log config that exposes tracebacks to end users.\n\nDetection hints:\n\n* Search for `debug=True`, `DEBUG = True`, environment flags mapped to debug.\n* Review exception middleware and error handler setup.\n\nFix:\n\n* Ensure debug is only enabled in local dev/test.\n* Return generic error responses to clients; log details internally.\n\n---\n\n### FASTAPI-OPENAPI-001: OpenAPI and interactive docs MUST be disabled or protected in production\n\nSeverity: Medium (can be High in sensitive/internal apps)\n\nRequired:\n\n* SHOULD disable `/docs`, `/redoc`, and `/openapi.json` in production for public-facing services unless there is an explicit business need.\n* If enabled, MUST protect them (e.g., auth, network allowlists, or internal-only routing).\n* MUST NOT assume “security through obscurity”; treat docs exposure as an information disclosure amplifier.\n\nInsecure patterns:\n\n* Publicly reachable `/docs` and `/openapi.json` for internal/admin APIs.\n* Docs enabled on the same hostname as production without access control.\n\nDetection hints:\n\n* Look for `FastAPI(docs_url=..., redoc_url=..., openapi_url=...)` or defaults.\n* Check reverse proxy routing and allowlists.\n\nFix:\n\n* Disable docs endpoints in prod (`docs_url=None`, `redoc_url=None`, `openapi_url=None`) or restrict access at the edge.\n\n---\n\n### FASTAPI-AUTH-001: Authentication MUST be explicit and consistently enforced via dependencies\n\nSeverity: High\n\nRequired:\n\n* MUST implement authentication as a dependency (or router-level dependency) so that protected endpoints cannot “forget” auth.\n* MUST default to “deny” for privileged routers/endpoints; explicitly mark truly public routes.\n* SHOULD centralize auth enforcement at router boundaries (e.g., protected `APIRouter` for authenticated endpoints). ([FastAPI][7])\n\nInsecure patterns:\n\n* Per-route ad-hoc auth checks scattered through handlers (easy to miss).\n* A mix of protected/unprotected endpoints with no clear policy.\n\nDetection hints:\n\n* Identify routers and endpoints; check whether protected ones include `Depends(...)`/`Security(...)`.\n* Search for patterns like `if user is None: raise ...` inside handlers (instead of dependencies).\n\nFix:\n\n* Move authentication into a dependency and attach it to the router/endpoint consistently using `Depends()`/`Security()`. ([FastAPI][7])\n\n---\n\n### FASTAPI-AUTH-002: Use standard auth transports; avoid secrets in URLs\n\nSeverity: High\n\nRequired:\n\n* SHOULD use the `Authorization: Bearer <token>` header for token auth, not query parameters. ([FastAPI][11])\n* MUST NOT place secrets (tokens, reset links containing long-lived secrets, API keys) in query strings when avoidable.\n\nInsecure patterns:\n\n* `?token=...`, `?api_key=...`, `?auth=...` used for primary auth.\n* Long-lived access tokens embedded in URLs (leak via logs, referrers, caches).\n\nDetection hints:\n\n* Search for parameter names like `token`, `api_key`, `key`, `secret`, `password`.\n* Look for security schemes that use query API keys without justification.\n\nFix:\n\n* Move tokens to Authorization headers; rotate/shorten lifetimes; use POST bodies for sensitive values.\n\n---\n\n### FASTAPI-AUTH-003: Password storage MUST be strongly hashed; never store plaintext passwords\n\nSeverity: Critical\n\nRequired:\n\n* MUST store passwords using a strong, slow password hashing scheme (e.g., Argon2id, bcrypt).\n* MUST NOT store plaintext passwords, or reversible encryption as the primary protection.\n* SHOULD use established libraries for hashing and verification (do not roll your own).\n\nInsecure patterns:\n\n* Storing plaintext passwords in DB.\n* Using fast hashes (e.g., SHA256) without a proper password hashing KDF.\n* Returning password hashes in API responses.\n\nDetection hints:\n\n* Search for `password=` persisted fields, and look for `hashlib.md5/sha1/sha256` usage on passwords.\n* Inspect response models for password/hash fields.\n\nFix:\n\n* Migrate to a proper password hashing library; add a re-hash-on-login upgrade path.\n\n---\n\n### FASTAPI-AUTH-004: JWT validation MUST be strict; JWTs MUST NOT carry secrets\n\nSeverity: High\n\nRequired:\n\n* MUST validate JWT signature and enforce an algorithm allowlist.\n* MUST validate standard claims appropriate to your system (at least `exp`; typically also `iss`/`aud` if multi-service or multi-tenant).\n* MUST treat JWT contents as readable by the client; do not put secrets in JWT payloads. ([FastAPI][12])\n\nInsecure patterns:\n\n* `jwt.decode(..., options={\"verify_signature\": False})` or equivalent.\n* Accepting `alg=none` / algorithm confusion.\n* Using JWT payload to store sensitive secrets (API keys, passwords).\n\nDetection hints:\n\n* Search for `jwt.decode`, `python-jose`, `PyJWT`, `verify_signature`.\n* Check for missing exp validation or long expirations.\n\nFix:\n\n* Enforce strict validation (signature, allowed algorithms, exp, and any required issuer/audience constraints).\n* Store only identifiers/claims you are comfortable exposing to the client. ([FastAPI][12])\n\n---\n\n### FASTAPI-AUTHZ-001: Authorization MUST be enforced per-object and per-property\n\nSeverity: High\n\nRequired:\n\n* MUST perform object-level authorization whenever accessing a resource by user-controlled identifier (ID in path/query/body).\n* MUST perform property-level authorization and response shaping to prevent “excessive data exposure” (e.g., admin-only fields). ([OWASP Foundation][13])\n\nInsecure patterns:\n\n* `GET /users/{id}` returns user record without verifying caller can access that `id`.\n* Response models include internal fields (roles, permissions, billing data, password hashes).\n\nDetection hints:\n\n* Enumerate endpoints that accept IDs; trace whether an authz check is performed.\n* Compare response models for public vs internal fields.\n\nFix:\n\n* Add object-level checks (ownership, ACLs, tenant boundaries).\n* Use dedicated response models that include only allowed fields.\n\n---\n\n### FASTAPI-SESS-001: If using cookie-based sessions and TLS, cookie attributes MUST be secure in production\n\nSeverity: High (only if TLS is enabled)\n\nRequired (production, HTTPS):\n\n* MUST set session cookies to be sent only over HTTPS (secure). IMPORTANT NOTE: Only set `Secure` in production environment when TLS is configured. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n* MUST set HttpOnly for session cookies (not accessible to JS).\n* SHOULD use `SameSite=Lax` (or `Strict` if UX allows); if you require cross-site cookies, document the CSRF implications and add compensating controls. ([OWASP Cheat Sheet Series][8])\n* If using Starlette `SessionMiddleware`, MUST set `https_only=True` in production and choose an appropriate `same_site`. ([PyPI][5])\n\nInsecure patterns:\n\n* Session cookies without Secure/HttpOnly.\n* `SameSite=None` cookies used for authenticated state-changing endpoints without CSRF protections.\n\nDetection hints:\n\n* Search for `SessionMiddleware(` and inspect parameters like `https_only`, `same_site`.\n* Search for `set_cookie(` usage and cookie flags.\n\nFix:\n\n* Set secure cookie attributes; prefer short lifetimes for high-privilege sessions. ([OWASP Cheat Sheet Series][8])\n\n---\n\n### FASTAPI-SESS-002: Do not store sensitive secrets in signed session cookies\n\nSeverity: High\n\nRequired:\n\n* MUST assume cookie-based session data is readable by the client (signed ≠ encrypted); do not store secrets/PII unless encrypted server-side.\n* Store only opaque identifiers (e.g., session ID) or non-sensitive state in the cookie; store sensitive session state server-side. ([OWASP Cheat Sheet Series][8])\n\nInsecure patterns:\n\n* Storing access tokens, refresh tokens, or PII directly in cookie session payloads.\n* Treating “signed cookies” as confidential storage.\n\nDetection hints:\n\n* Search for `request.session[...] =` or `session[...] =`-equivalent patterns; identify what is stored.\n* Identify use of `SessionMiddleware` or other cookie session mechanisms.\n\nFix:\n\n* Move sensitive values to server-side storage; keep cookie minimal.\n\n---\n\n### FASTAPI-CSRF-001: Cookie-authenticated state-changing requests MUST be CSRF-protected\n\nSeverity: High\n\nNote: This only applies if using cookie based auth. If the application uses header or token based auth such as Authorization header, then CSRF is not an issue.\n\nRequired:\n\n* MUST protect all state-changing endpoints (POST/PUT/PATCH/DELETE) that rely on cookies for authentication.\n* SHOULD use a proven CSRF approach (synchronizer token pattern, or well-reviewed middleware) rather than rolling your own. ([OWASP Cheat Sheet Series][2])\n* MAY add defense-in-depth (Origin/Referer checks, SameSite cookies, Fetch Metadata), but tokens are the primary defense for cookie-authenticated apps. ([OWASP Cheat Sheet Series][2])\n* IMPORTANT NOTE: If cookies are not used for auth (auth is via `Authorization` header), CSRF is usually not applicable. ([FastAPI][11])\n\nInsecure patterns:\n\n* Cookie-authenticated endpoints that change state with no CSRF validation.\n* Using GET for state-changing actions (amplifies CSRF risk).\n\nDetection hints:\n\n* Enumerate routes with methods other than GET; identify whether cookies are used for auth.\n* Look for CSRF token generation/verification or middleware.\n\nFix:\n\n* Add CSRF tokens (and validate them) on state-changing actions when cookie auth is in use. ([OWASP Cheat Sheet Series][2])\n\n---\n\n### FASTAPI-VALID-001: Request parsing and validation MUST be schema-driven; prevent mass assignment\n\nSeverity: Medium (especially for APIs that write to DB)\n\nRequired:\n\n* SHOULD use Pydantic models for request bodies instead of accepting arbitrary `dict`/`Any`.\n* SHOULD configure models to reject unexpected fields where appropriate (prevents “mass assignment” style bugs).\n* MUST validate and normalize identifiers (IDs, email, URLs) before using them for access control or side effects. ([OWASP Cheat Sheet Series][14])\n\nInsecure patterns:\n\n* `payload = await request.json()` followed by `Model(**payload)` or direct DB writes with `payload` (no allowlist).\n* Models that silently accept unknown fields for write endpoints.\n\nDetection hints:\n\n* Search for `await request.json()`, `request.body()`, `dict`-typed bodies, `Any`-typed bodies.\n* Look for endpoints that do `db.update(**payload)` or `Model(**payload)` with unfiltered input.\n\nFix:\n\n* Use explicit Pydantic models with allowlisted fields; reject extras for write endpoints. ([OWASP Cheat Sheet Series][14])\n\n---\n\n### FASTAPI-RESP-001: Prevent excessive data exposure via response models and explicit serialization\n\nSeverity: Medium\n\nRequired:\n\n* MUST define response models that include only intended fields (especially for user objects, auth-related objects, billing objects).\n* SHOULD use separate models for “create input”, “db/internal”, and “public output” to avoid leaking sensitive fields. ([FastAPI][15])\n\nInsecure patterns:\n\n* Returning ORM objects or dicts that include internal columns.\n* Reusing “DB model” as the response model (includes `password_hash`, `is_admin`, etc).\n\nDetection hints:\n\n* Look for endpoints that `return user` where `user` is an ORM instance.\n* Check for `response_model` omissions on endpoints that return sensitive resources.\n\nFix:\n\n* Add explicit response models; create “public” schemas that exclude sensitive fields. ([FastAPI][15])\n\n---\n\n### FASTAPI-XSS-001: Prevent reflected/stored XSS in HTML responses and templates\n\nSeverity: High (if the service serves HTML)\n\nRequired:\n\n* MUST use templating with auto-escaping enabled for HTML.\n* MUST NOT mark untrusted content as safe (no unsafe “raw HTML” rendering of user-controlled data).\n* SHOULD deploy a CSP when serving HTML that includes any user content. ([OWASP Cheat Sheet Series][16])\n\nInsecure patterns:\n\n* Rendering user content directly into HTML without escaping/sanitization.\n* Disabling auto-escaping or using “raw HTML” features without sanitization.\n\nDetection hints:\n\n* Search for template rendering and string concatenation that builds HTML.\n* Review templates for “unsafe” filters/constructs and unquoted attributes.\n\nFix:\n\n* Keep auto-escaping on; sanitize user HTML only if absolutely required using a trusted sanitizer; add CSP. ([OWASP Cheat Sheet Series][16])\n\nNote:\n\n* If the app is a pure JSON API, XSS is usually a client/app concern, but error pages/docs pages might still render HTML.\n\n---\n\n### FASTAPI-SSTI-001: Never render untrusted templates (Server-Side Template Injection)\n\nSeverity: Critical\n\nRequired:\n\n* MUST NOT render templates that contain user-controlled template syntax.\n* MUST treat “template-from-string” rendering as dangerous if influenced by untrusted input.\n* If untrusted templates are absolutely required (rare, high-risk):\n\n  * MUST use a sandboxed templating approach and restrict capabilities.\n  * MUST assume sandbox escapes are possible; add isolation and strict allowlists. ([OWASP Foundation][17])\n\nInsecure patterns:\n\n* Rendering templates loaded from user input or DB via a normal Jinja environment.\n* Building templates dynamically using user-controlled strings.\n\nDetection hints:\n\n* Grep for Jinja `Environment.from_string`, `Template(...)`, or similar.\n* Trace origin of template string (request, DB, uploads, admin panels).\n\nFix:\n\n* Replace with non-executable templating (simple string substitution).\n* If truly needed, use Jinja’s sandbox environment plus strong isolation. ([jinja.palletsprojects.com][18])\n\n---\n\n### FASTAPI-HEADERS-001: Set essential security headers (in app or at the edge)\n\nSeverity: Medium\n\nRequired (typical API/web app):\n\n* SHOULD set:\n\n  * `X-Content-Type-Options: nosniff`\n  * Clickjacking protection (`X-Frame-Options` and/or CSP `frame-ancestors`) if HTML is served\n  * `Referrer-Policy` and `Permissions-Policy` as appropriate\n\nNOTE:\n\n* Headers may be set by a proxy/CDN. If not visible in app code, flag as “verify at edge”. ([OWASP Cheat Sheet Series][6])\n\nInsecure patterns:\n\n* No security headers anywhere (app or edge) for apps serving HTML or sensitive APIs.\n\nDetection hints:\n\n* Search for middleware that sets headers; check reverse proxy config.\n\nFix:\n\n* Set headers centrally (middleware) or via reverse proxy/CDN.\n\n---\n\n### FASTAPI-CORS-001: CORS MUST be explicit and least-privilege\n\nSeverity: Medium (High if misconfigured with credentials)\n\nRequired:\n\n* If CORS is not needed, MUST keep it disabled.\n* If CORS is needed:\n\n  * MUST allowlist trusted origins (do not reflect arbitrary origins).\n  * MUST NOT combine credentialed requests with wildcard origins (this is unsafe and commonly rejected by compliant middleware). ([OWASP Cheat Sheet Series][6])\n  * SHOULD restrict allowed methods and headers.\n\nInsecure patterns:\n\n* `allow_origins=[\"*\"]` together with `allow_credentials=True`.\n* Reflecting `Origin` without validation.\n* `allow_origin_regex=\".*\"` used broadly.\n\nDetection hints:\n\n* Search for `CORSMiddleware` configuration.\n* Look for `allow_origins=[\"*\"]`, `allow_credentials=True`, `allow_origin_regex`.\n\nFix:\n\n* Use an explicit origin allowlist and minimal methods/headers; keep credentials off unless required. ([OWASP Cheat Sheet Series][6])\n\n---\n\n### FASTAPI-HOST-001: Host header MUST be validated in production\n\nSeverity: Low\n\nRequired:\n\n* SHOULD use `TrustedHostMiddleware` (or equivalent at edge) to restrict accepted Host values. ([PyPI][5])\n* MUST NOT trust the `Host` header for security-sensitive decisions without validation.\n\nInsecure patterns:\n\n* No Host validation while generating external URLs (password reset links, callback URLs) from request host.\n* Allowing arbitrary Host headers in apps behind permissive proxies.\n\nDetection hints:\n\n* Search for `TrustedHostMiddleware` usage.\n* Search for logic that uses `request.url`, `request.base_url`, or host-derived values to build external URLs.\n\nFix:\n\n* Configure a strict allowed-hosts list in production; enforce at edge too if possible.\n\n---\n\n### FASTAPI-PROXY-001: Reverse proxy trust MUST be configured correctly\n\nSeverity: High (when behind a proxy)\n\nRequired:\n\n* If behind a reverse proxy, MUST configure forwarded-header trust correctly.\n* MUST NOT blindly trust `X-Forwarded-*` headers from the open internet.\n* If using Uvicorn proxy header support, MUST restrict which IPs are allowed to provide forwarded headers. ([PyPI][4])\n\nInsecure patterns:\n\n* Enabling proxy headers broadly without restricting trusted proxy IPs.\n* Using forwarded headers to decide “is secure” / “is internal” / “client IP” without proper trust boundaries.\n\nDetection hints:\n\n* Search for `--proxy-headers`, `--forwarded-allow-ips`, or equivalent config.\n* Search for security-sensitive use of `request.client.host`, `request.url.scheme`, `request.headers[\"x-forwarded-for\"]`.\n\nFix:\n\n* Configure Uvicorn with proxy headers only when behind a known proxy, and restrict `forwarded_allow_ips` to that proxy. ([PyPI][4])\n* Keep Host allowlisting in place even behind proxies.\n\n---\n\n### FASTAPI-LIMITS-001: Request and multipart limits MUST be enforced to prevent DoS\n\nSeverity: Low\n\nRequired:\n\n* MUST enforce request size limits at the edge (reverse proxy/load balancer) and validate in app where needed.\n* MUST apply special scrutiny to multipart/form-data handling; historical vulnerabilities include unbounded buffering and DoS vectors. ([advisories.gitlab.com][9])\n* SHOULD rate limit and/or add per-IP/per-user throttles for expensive endpoints.\n\nInsecure patterns:\n\n* Accepting arbitrarily large JSON bodies or multipart forms.\n* Parsing multipart forms without size/field-count controls.\n\nDetection hints:\n\n* Identify file upload endpoints and `multipart/form-data` usage.\n* Look for missing proxy-level limits (nginx `client_max_body_size`, ALB limits, etc.) and missing app-level checks.\n\nFix:\n\n* Enforce strict body limits and multipart constraints; keep Starlette and python-multipart updated to patched versions. ([advisories.gitlab.com][9])\n\n---\n\n### FASTAPI-FILES-001: Prevent path traversal and unsafe static file exposure\n\nSeverity: High\n\nRequired:\n\n* MUST NOT pass user-controlled file paths to `FileResponse`/filesystem calls without strict validation and safe base directories.\n* If using `StaticFiles`, MUST keep Starlette updated and understand the security history (path traversal advisory exists for older versions). ([advisories.gitlab.com][10])\n* MUST NOT serve user uploads as executable/active content (especially HTML/JS) from a static root without safe handling.\n\nInsecure patterns:\n\n* `FileResponse(request.query_params[\"path\"])`\n* Mounting `StaticFiles(directory=\"uploads\")` where uploads include HTML/JS/SVG and are served inline.\n\nDetection hints:\n\n* Search for `FileResponse(`, `StaticFiles(`, `open(` in routes.\n* Trace whether the path originates from untrusted input.\n\nFix:\n\n* Use opaque IDs for files; map IDs to server-side stored paths.\n* Serve untrusted content as attachment downloads where appropriate.\n\n---\n\n### FASTAPI-FILES-002: Mitigate Range-header DoS on file-serving endpoints\n\nSeverity: Low (if affected versions and file serving is enabled)\n\nRequired:\n\n* MUST keep Starlette patched against known file-serving DoS issues if using `FileResponse`/`StaticFiles`.\n* MUST treat unusual `Range` header handling and file serving as a DoS surface. ([advisories.gitlab.com][19])\n\nInsecure patterns:\n\n* Serving large files with vulnerable Starlette versions.\n* No rate limiting / CDN shielding for file endpoints.\n\nDetection hints:\n\n* Identify Starlette version; if in affected range, flag.\n* Find uses of `FileResponse` and `StaticFiles`.\n\nFix:\n\n* Upgrade Starlette to a fixed version per advisory guidance. ([advisories.gitlab.com][19])\n* Add edge caching/rate limiting for file endpoints where appropriate.\n\n---\n\n### FASTAPI-UPLOAD-001: File uploads MUST be validated, stored safely, and served safely\n\nSeverity: Medium\n\nRequired:\n\n* MUST enforce upload size limits (app + edge).\n* MUST validate file type using allowlists and content checks (not only extension). ([OWASP Cheat Sheet Series][20])\n* SHOULD generate server-side filenames (random IDs) and avoid trusting original names.\n* MUST serve potentially active formats safely (download attachment) unless explicitly intended.\n\nInsecure patterns:\n\n* Accepting arbitrary file types and serving them back inline.\n* Using user-supplied filename as storage path.\n\nDetection hints:\n\n* Look for upload handlers and where/how files are written.\n* Look for direct exposure of upload directories.\n\nFix:\n\n* Implement allowlist validation + safe storage + safe serving; add scanning/quarantine if applicable. ([OWASP Cheat Sheet Series][20])\n\n---\n\n### FASTAPI-INJECT-001: Prevent SQL injection (use parameterized queries / ORM)\n\nSeverity: High\n\nRequired:\n\n* MUST use parameterized queries or an ORM that parameterizes under the hood.\n* MUST NOT build SQL by string concatenation / f-strings with untrusted input. ([OWASP Cheat Sheet Series][21])\n\nInsecure patterns:\n\n* `f\"SELECT ... WHERE id={user_id}\"`\n* `\"... WHERE name = '%s'\" % user_input`\n\nDetection hints:\n\n* Grep for SQL keywords in Python strings near `.execute(...)`.\n* Trace untrusted data into DB calls.\n\nFix:\n\n* Replace with parameterized queries / ORM query APIs; validate types before querying. ([OWASP Cheat Sheet Series][21])\n\n---\n\n### FASTAPI-INJECT-002: Prevent OS command injection\n\nSeverity: Critical to High (depends on exposure)\n\nRequired:\n\n* MUST avoid executing shell commands with untrusted input.\n* If subprocess is necessary:\n\n  * MUST pass args as a list (not a string)\n  * MUST NOT use `shell=True` with attacker-influenced strings\n  * SHOULD use strict allowlists for any variable component ([OWASP Cheat Sheet Series][22])\n\nInsecure patterns:\n\n* `os.system(user_input)`\n* `subprocess.run(f\"cmd {user}\", shell=True)`\n* Passing user strings into `bash -c`, `sh -c`, PowerShell, etc.\n\nDetection hints:\n\n* Search for `os.system`, `subprocess`, `Popen`, `shell=True`.\n* Trace data from request/DB into these calls.\n\nFix:\n\n* Use library APIs instead of shell commands.\n* If unavoidable, hard-code the command and allowlist validated parameters; use `--` separator where supported. ([OWASP Cheat Sheet Series][22])\n\n---\n\n### FASTAPI-SSRF-001: Prevent server-side request forgery (SSRF) in outbound HTTP\n\nSeverity: Medium (can be High in cloud/VPC environments)\n\n- Note: For small stand alone projects this is less important. It is most important when deploying into an LAN or with other services listening on the same server.\n\nRequired:\n\n* MUST treat outbound requests to user-provided URLs as high risk.\n* SHOULD validate and restrict destinations (allowlist hosts/domains) for any user-influenced URL fetch.\n* SHOULD block access to localhost/private IP ranges/link-local and cloud metadata endpoints.\n* MUST restrict protocols to http/https.\n* SHOULD set timeouts and carefully control redirects. ([OWASP Cheat Sheet Series][23])\n\nInsecure patterns:\n\n* `httpx.get(request.query_params[\"url\"])`\n* “URL preview/import/webhook tester” features that accept arbitrary URLs.\n\nDetection hints:\n\n* Search for `requests`, `httpx`, `urllib`, `aiohttp` calls with URLs derived from requests/DB.\n* Identify endpoints named `fetch`, `preview`, `proxy`, `webhook`, `import`.\n\nFix:\n\n* Implement strict URL parsing + allowlists; add egress controls; set short timeouts; disable redirects if not required. ([OWASP Cheat Sheet Series][23])\n\n---\n\n### FASTAPI-REDIRECT-001: Prevent open redirects\n\nSeverity: Low\n\nRequired:\n\n* MUST validate redirect targets derived from untrusted input (`next`, `redirect`, `return_to`).\n* SHOULD prefer redirecting only to same-site relative paths or an allowlist of domains. ([OWASP Cheat Sheet Series][24])\n\nInsecure patterns:\n\n* Returning `RedirectResponse(next)` where `next` is user-controlled with no validation.\n\nDetection hints:\n\n* Search for `RedirectResponse(` or redirect logic and examine the source of the target.\n\nFix:\n\n* Allow only relative paths or allowlisted domains; fall back to a safe default. ([OWASP Cheat Sheet Series][24])\n\n---\n\n### FASTAPI-WS-001: WebSocket endpoints MUST be authenticated and protected against cross-site abuse\n\nSeverity: Medium to High (depends on data/privilege)\n\nRequired:\n\n* MUST authenticate WebSocket connections for any non-public channel (WebSockets don’t inherently provide auth). ([OWASP Cheat Sheet Series][25])\n* SHOULD enforce origin/CSRF-like protections appropriate for browser-based WebSocket clients (Origin validation is a common control).\n* SHOULD rate limit message frequency and connection attempts; close idle/abusive connections.\n\nInsecure patterns:\n\n* `@app.websocket(...)` accepts and trusts the connection with no auth check.\n* Using query-string tokens for auth without considering leakage/rotation.\n\nDetection hints:\n\n* Search for `@app.websocket` / `websocket_endpoint` and inspect whether auth is performed before accepting sensitive operations.\n* Review origin checks, token parsing, and per-connection authorization.\n\nFix:\n\n* Require authentication during handshake (e.g., a token or session) and enforce authorization for actions/messages.\n* Validate Origin for browser-based clients where appropriate; apply rate limits and timeouts. ([OWASP Cheat Sheet Series][25])\n\n---\n\n### FASTAPI-SUPPLY-001: Dependency and patch hygiene (focus on security-relevant deps)\n\nSeverity: Low\n\nRequired:\n\n* SHOULD pin and regularly update security-critical dependencies (FastAPI, Starlette, Uvicorn, Pydantic, python-multipart, auth/JWT libs).\n* MUST respond to known security advisories promptly.\n* MUST treat file serving and multipart parsing dependencies as security-sensitive due to historical CVEs. ([advisories.gitlab.com][10])\n\nAudit focus examples (historical):\n\n* Starlette StaticFiles path traversal (fixed in 0.27.0). ([advisories.gitlab.com][10])\n* Starlette multipart/form-data DoS (fixed in 0.40.0). ([advisories.gitlab.com][9])\n* Starlette FileResponse Range header DoS (fixed in 0.49.1). ([advisories.gitlab.com][19])\n\nDetection hints:\n\n* Check `requirements.txt`, lockfiles, container images, and runtime environments for actual installed versions.\n* Map file upload/file serving features to dependency versions.\n\nFix:\n\n* Upgrade to patched versions per advisories; add regression tests around affected behavior.\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* Dev server / debug:\n\n  * `--reload`, `reload=True`, `debug=True`, `FastAPI(debug=True)` ([PyPI][4])\n* OpenAPI/docs exposure:\n\n  * `/docs`, `/redoc`, `/openapi.json`, `docs_url=`, `openapi_url=`\n* Auth enforcement gaps:\n\n  * Endpoints missing `Depends()`/`Security()` where expected; routers without a consistent dependency boundary ([FastAPI][7])\n  * Tokens in query params (`token=`, `api_key=`, `key=`) ([FastAPI][11])\n* Session/cookies + CSRF:\n\n  * `SessionMiddleware(` and cookie flags (`https_only`, `same_site`) ([PyPI][5])\n  * POST/PUT/PATCH/DELETE handlers using cookie auth with no CSRF checks ([OWASP Cheat Sheet Series][2])\n* Input validation & mass assignment:\n\n  * `await request.json()` and direct DB writes from dicts; models accepting extra fields ([OWASP Cheat Sheet Series][14])\n* Excessive data exposure:\n\n  * Returning ORM objects or dicts without `response_model`; responses containing password/role/internal fields ([FastAPI][15])\n* CORS:\n\n  * `CORSMiddleware` with `allow_origins=[\"*\"]`, `allow_origin_regex=\".*\"`, `allow_credentials=True` ([OWASP Cheat Sheet Series][6])\n* Files:\n\n  * `FileResponse(` with user-controlled paths; `StaticFiles(` exposing uploads ([advisories.gitlab.com][10])\n* Uploads / multipart:\n\n  * `multipart/form-data` endpoints with no size/field constraints; outdated Starlette/python-multipart ([advisories.gitlab.com][9])\n* Injection:\n\n  * SQL strings with f-strings/concatenation into `.execute(...)` ([OWASP Cheat Sheet Series][21])\n  * `subprocess.*`, `shell=True`, `os.system` ([OWASP Cheat Sheet Series][22])\n* SSRF:\n\n  * `httpx.get/post` or `requests.*` with URL from request/DB, no allowlist/timeouts ([OWASP Cheat Sheet Series][23])\n* Redirect:\n\n  * `RedirectResponse(next)` with no validation ([OWASP Cheat Sheet Series][24])\n* WebSockets:\n\n  * `@app.websocket` handlers without auth/origin checks; use of `ws://` in prod configs ([FastAPI][27])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (SQL/subprocess/files/template/http/redirect/ws)\n* protective controls present (validation, allowlists, middleware, edge controls)\n* installed dependency versions vs vulnerable ranges ([advisories.gitlab.com][10])\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary framework documentation:\n\n* FastAPI (PyPI metadata, versioning) — `https://pypi.org/project/fastapi/` ([PyPI][1])\n* FastAPI docs: Security “First Steps” (Authorization Bearer header conventions) — `https://fastapi.tiangolo.com/tutorial/security/first-steps/` ([FastAPI][11])\n* FastAPI reference: Dependencies (`Depends`, `Security`) — `https://fastapi.tiangolo.com/reference/dependencies/` ([FastAPI][7])\n* FastAPI reference: APIRouter (router-level dependencies) — `https://fastapi.tiangolo.com/reference/apirouter/` ([FastAPI][28])\n* FastAPI docs: WebSockets — `https://fastapi.tiangolo.com/advanced/websockets/` ([FastAPI][27])\n\nASGI/server stack documentation:\n\n* Starlette (PyPI, general capabilities) — `https://pypi.org/project/starlette/` ([PyPI][5])\n* Starlette docs: WebSockets — `https://starlette.dev/websockets/` ([Starlette][3])\n* Uvicorn (PyPI metadata) — `https://pypi.org/project/uvicorn/` ([PyPI][4])\n* Pydantic docs (v2.12.x) — `https://docs.pydantic.dev/latest/` ([Pydantic][29])\n\nSecurity standards and cheat sheets:\n\n* OWASP Cheat Sheet Series: Session Management — `https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][8])\n* OWASP Cheat Sheet Series: CSRF Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][2])\n* OWASP Cheat Sheet Series: XSS Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][16])\n* OWASP Cheat Sheet Series: Mass Assignment — `https://cheatsheetseries.owasp.org/cheatsheets/Mass_Assignment_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][14])\n* OWASP API Security Top 10 (2023) — `https://owasp.org/API-Security/editions/2023/en/0x11-t10/` ([OWASP Foundation][13])\n* OWASP Cheat Sheet Series: SQL Injection Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][21])\n* OWASP Cheat Sheet Series: OS Command Injection Defense — `https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][22])\n* OWASP Cheat Sheet Series: SSRF Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][23])\n* OWASP Cheat Sheet Series: File Upload — `https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][20])\n* OWASP Cheat Sheet Series: Unvalidated Redirects and Forwards — `https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][24])\n* OWASP Cheat Sheet Series: HTTP Security Response Headers — `https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][6])\n* OWASP Cheat Sheet Series: WebSocket Security — `https://cheatsheetseries.owasp.org/cheatsheets/WebSocket_Security_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][25])\n* OWASP WSTG: Testing for Server-Side Template Injection — `https://owasp.org/www-project-web-security-testing-guide/v41/4-Web_Application_Security_Testing/07-Input_Validation_Testing/18-Testing_for_Server_Side_Template_Injection` ([OWASP Foundation][17])\n* OWASP WSTG: Testing WebSockets — `https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/11-Client-side_Testing/10-Testing_WebSockets` ([OWASP Foundation][26])\n\nTemplate safety references:\n\n* Jinja: Sandbox — `https://jinja.palletsprojects.com/en/stable/sandbox/` ([jinja.palletsprojects.com][18])\n\nSelected supply-chain/advisory references (Starlette examples):\n\n* CVE-2023-29159 (StaticFiles path traversal; fixed 0.27.0) — `https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2023-29159/` ([advisories.gitlab.com][10])\n* CVE-2024-47874 (multipart/form-data DoS; fixed 0.40.0) — `https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2024-47874/` ([advisories.gitlab.com][9])\n* CVE-2025-62727 (FileResponse Range header DoS; fixed 0.49.1) — `https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2025-62727/` ([advisories.gitlab.com][19])\n\n[1]: https://pypi.org/project/fastapi/ \"https://pypi.org/project/fastapi/\"\n[2]: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html\"\n[3]: https://starlette.dev/websockets/?utm_source=chatgpt.com \"Websockets\"\n[4]: https://pypi.org/project/uvicorn/ \"https://pypi.org/project/uvicorn/\"\n[5]: https://pypi.org/project/starlette/ \"https://pypi.org/project/starlette/\"\n[6]: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html?utm_source=chatgpt.com \"HTTP Security Response Headers Cheat Sheet\"\n[7]: https://fastapi.tiangolo.com/reference/dependencies/?utm_source=chatgpt.com \"Dependencies - Depends() and Security() - FastAPI\"\n[8]: https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html\"\n[9]: https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2024-47874/ \"Starlette Denial of service (DoS) via multipart/form-data | GitLab Advisory Database\"\n[10]: https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2023-29159/ \"Starlette has Path Traversal vulnerability in StaticFiles | GitLab Advisory Database\"\n[11]: https://fastapi.tiangolo.com/tutorial/security/first-steps/?utm_source=chatgpt.com \"Security - First Steps - FastAPI\"\n[12]: https://fastapi.tiangolo.com/tutorial/response-model/ \"https://fastapi.tiangolo.com/tutorial/response-model/\"\n[13]: https://owasp.org/API-Security/editions/2023/en/0x11-t10/ \"https://owasp.org/API-Security/editions/2023/en/0x11-t10/\"\n[14]: https://cheatsheetseries.owasp.org/cheatsheets/Mass_Assignment_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Mass_Assignment_Cheat_Sheet.html\"\n[15]: https://fastapi.tiangolo.com/tutorial/extra-models/ \"https://fastapi.tiangolo.com/tutorial/extra-models/\"\n[16]: https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html\"\n[17]: https://owasp.org/www-project-web-security-testing-guide/v41/4-Web_Application_Security_Testing/07-Input_Validation_Testing/18-Testing_for_Server_Side_Template_Injection?utm_source=chatgpt.com \"Testing for Server Side Template Injection\"\n[18]: https://jinja.palletsprojects.com/en/stable/sandbox/?utm_source=chatgpt.com \"Sandbox — Jinja Documentation (3.1.x)\"\n[19]: https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2025-62727/ \"Starlette vulnerable to O(n^2) DoS via Range header merging in ``starlette.responses.FileResponse`` | GitLab Advisory Database\"\n[20]: https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html\"\n[21]: https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html\"\n[22]: https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html\"\n[23]: https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html\"\n[24]: https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html?utm_source=chatgpt.com \"Unvalidated Redirects and Forwards Cheat Sheet\"\n[25]: https://cheatsheetseries.owasp.org/cheatsheets/WebSocket_Security_Cheat_Sheet.html?utm_source=chatgpt.com \"WebSocket Security - OWASP Cheat Sheet Series\"\n[26]: https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/11-Client-side_Testing/10-Testing_WebSockets?utm_source=chatgpt.com \"WSTG - Latest | OWASP Foundation\"\n[27]: https://fastapi.tiangolo.com/advanced/websockets/?utm_source=chatgpt.com \"WebSockets - FastAPI\"\n[28]: https://fastapi.tiangolo.com/reference/apirouter/?utm_source=chatgpt.com \"APIRouter class - FastAPI\"\n[29]: https://docs.pydantic.dev/latest/ \"https://docs.pydantic.dev/latest/\"\n","isInternal":false,"tokens":10420,"sizeBytes":44926},{"name":"python-flask-web-server-security.md","path":"core/skills/builtin/security-best-practices/references/python-flask-web-server-security.md","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/security-best-practices/references/python-flask-web-server-security.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Flask (Python) Web Security Spec (Flask 3.1.x, Python 3.x)\n\nThis document is designed as a **security spec** that supports:\n1) **Secure-by-default code generation** for new Flask code.\n2) **Security review / vulnerability hunting** in existing Flask code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n--------------------------------------------------------------------\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n- MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session cookies, SECRET_KEY).\n- MUST NOT “fix” security by disabling protections (e.g., turning off CSRF, relaxing CORS, disabling escaping, disabling auth checks).\n- MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and configuration values that justify the claim.\n- MUST treat uncertainty honestly: if a protection might exist in infrastructure (reverse proxy, WAF, CDN), report it as “not visible in app code; verify at runtime/config”.\n\n--------------------------------------------------------------------\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\nWhen asked to write new Flask code or modify existing code:\n- MUST follow every **MUST** requirement in this spec.\n- SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n- MUST prefer safe-by-default APIs and proven libraries over custom security code.\n- MUST avoid introducing new risky sinks (template rendering from strings, shell execution, dynamic imports, unsafe redirects, serving user files as HTML, etc.).\n\n### 1.2 Passive review mode (always on while editing)\nWhile working anywhere in a Flask repo (even if the user did not ask for a security scan):\n- MUST “notice” violations of this spec in touched/nearby code.\n- SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n- MUST systematically search the codebase for violations of this spec.\n- MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n1) App entrypoints / deployment scripts / Dockerfiles / Procfiles.\n2) Flask configuration and environment handling.\n3) Auth + sessions + cookies.\n4) CSRF protections and state-changing routes.\n5) Template rendering and XSS/SSTI.\n6) File handling (uploads + downloads) and path traversal.\n7) Injection classes (SQL, command execution, unsafe deserialization).\n8) Outbound requests (SSRF).\n9) Redirect handling (open redirects).\n10) CORS and security headers.\n\n--------------------------------------------------------------------\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\nExamples include:\n- `request.args`, `request.form`, `request.values`\n- `request.get_json()`, `request.json`, `request.data`\n- `request.headers`, `request.cookies`\n- URL path parameters (e.g., `/user/<id>`)\n- Any data from external systems (webhooks, third-party APIs, message queues)\n- Any persisted user content (DB rows) that originated from users\n\n### 2.2 State-changing request\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook send), or initiate privileged actions.\n\n### 2.3 Required audit finding format\nFor each issue found, output:\n\n- Rule ID:\n- Severity: Critical / High / Medium / Low\n- Location: file path + function/route name + line(s)\n- Evidence: the exact code/config snippet\n- Impact: what could go wrong, who can exploit it\n- Fix: safe change (prefer minimal diff)\n- Mitigation: defense-in-depth if immediate fix is hard\n- False positive notes: what to verify if uncertain\n\n--------------------------------------------------------------------\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common Flask misconfigurations.\n\n### 3.1 App initialization pattern (SHOULD)\nSHOULD use an app factory and environment-based config so production config is not hard-coded.\n\nExample skeleton (illustrative; adjust to your project):\n- Load config from environment / secret store.\n- Fail closed if critical settings are missing in production.\n\nKey baseline config targets:\n- `SECRET_KEY` set and not committed\n- `SESSION_COOKIE_SECURE=True` (when HTTPS) IMPORTANT NOTE: Only set `Secure` in production environment when TLS is configured. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n- `SESSION_COOKIE_HTTPONLY=True`\n- `SESSION_COOKIE_SAMESITE='Lax'` (or `'Strict'` if compatible)\n- `TRUSTED_HOSTS` set in production\n- Security headers set (CSP, etc.) either in app or at the edge\n\n--------------------------------------------------------------------\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### FLASK-DEPLOY-001: Do not use Flask’s development server in production\nSeverity: High (if production)\n\nRequired:\n- MUST NOT deploy the built-in development server as the production server.\n- MUST run behind a production-grade WSGI server or managed platform (such as gunicorn)\n\nInsecure patterns:\n- `app.run(...)` in a production entrypoint.\n- Deployment docs/scripts that use `flask run` in production.\n\nDetection hints:\n- Search for `app.run(`, `flask run`, `--debug`, `FLASK_DEBUG`, `FLASK_ENV=development`.\n- Check Docker CMD/ENTRYPOINT, Procfile, systemd units, shell scripts.\n\nFix:\n- Use a production WSGI server (and keep Flask as the app object).\n- Ensure the dev server is only used for local development.\n\nNote:\n- These are often used in dev mode or local testing. This is allowed. Only flag if it is clear that it is being used as the production entrypoint\n\n---\n\n### FLASK-DEPLOY-002: Debug mode MUST be disabled in production\nSeverity: Critical\n\nRequired:\n- MUST NOT enable debug mode in production.\n- MUST treat the interactive debugger as equivalent to remote code execution if exposed.\n\nInsecure patterns:\n- `app.run(debug=True)`\n- `flask run --debug` in production.\n- `DEBUG=True` via env/config in production.\n\nDetection hints:\n- Look for `debug=True`, `FLASK_DEBUG=1`, `DEBUG = True`, `app.debug = True`.\n- Look for `TRAP_HTTP_EXCEPTIONS`/debugger settings enabled in non-test contexts.\n\nFix:\n- Ensure debug is only enabled in local dev/test.\n- Prefer environment-based toggles and safe defaults.\n\nNote:\n- These are often used in dev mode or local testing. This is allowed. Only flag if it is clear that it is being used as the production entrypoint\n\n---\n\n### FLASK-CONFIG-001: SECRET_KEY must be strong, secret, and rotated safely\nSeverity: High (Critical if missing in production with sessions or signing)\n\nRequired:\n- MUST set a strong random `SECRET_KEY` in production.\n- MUST keep `SECRET_KEY` out of source control and out of logs.\n- MAY rotate keys periodically; MAY use `SECRET_KEY_FALLBACKS` to support rotation without instantly invalidating existing sessions, then remove old keys after the rotation window. This likely is not needed for smaller applications but is good practice for larger applications. As this may complicate deployment, suggest that it be implemented rather than implementing it by default.\n\nInsecure patterns:\n- Missing `SECRET_KEY` in production.\n- Hard-coded `SECRET_KEY` in repo (including test keys accidentally used in prod).\n- Logging or printing `SECRET_KEY`.\n\nDetection hints:\n- Search for `SECRET_KEY =`, `app.secret_key =`, `SECRET_KEY_FALLBACKS =`.\n- Check `.env` files committed to repo.\n- Check config modules for constants.\n\nFix:\n- Load from secret manager or environment variable.\n- Add a rotation process:\n  - Set new `SECRET_KEY`\n  - Keep old key(s) temporarily in `SECRET_KEY_FALLBACKS`\n  - Remove old key(s) after the safe window.\n\nNotes:\n- If the application uses Flask sessions (cookie-based by default), `SECRET_KEY` is directly security-critical.\n\n---\n\n### FLASK-SESS-001: Session cookies must use secure attributes in production\nSeverity: Medium\n\nRequired (production, HTTPS):\n- MUST set `SESSION_COOKIE_SECURE=True` (cookies only over HTTPS). NOTE: Only set `Secure` in production environment when TLS is configured. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n- MUST ensure `SESSION_COOKIE_HTTPONLY=True` (protect from JS access).\n- SHOULD set `SESSION_COOKIE_SAMESITE='Lax'` (recommended) or `'Strict'` if compatible with UX.\n- SHOULD keep `SESSION_COOKIE_DOMAIN=None` unless you explicitly need subdomain-wide cookies.\n- If you need embedded/iframe third-party usage, MAY consider `SESSION_COOKIE_PARTITIONED=True` (requires HTTPS).\n\nInsecure patterns:\n- `SESSION_COOKIE_SECURE=False` in production.\n- `SESSION_COOKIE_HTTPONLY=False`.\n- `SESSION_COOKIE_SAMESITE=None` with cookie-authenticated state-changing endpoints (higher CSRF risk).\n\nDetection hints:\n- Inspect `app.config.update(...)` blocks and config classes.\n- Look for `set_cookie(..., secure=..., httponly=..., samesite=...)` usage on non-session cookies too.\n\nFix:\n- Set these config values explicitly in production config.\n\nNotes:\n- SameSite is defense-in-depth; do not treat it as a full replacement for CSRF tokens.\n\n---\n\n### FLASK-SESS-002: Sessions must be bounded and resistant to fixation/replay\nSeverity: Medium\n\nRequired:\n- SHOULD set a bounded session lifetime appropriate to the app.\n- SHOULD set `session.permanent = True` only when you intend persistent sessions, and set `PERMANENT_SESSION_LIFETIME` to a justified value.\n- SHOULD clear the session on login and privilege changes to reduce session fixation risk.\n- MUST NOT store sensitive secrets in the default Flask session cookie. The default session is signed, not encrypted.\n\nInsecure patterns:\n- Extremely long or unlimited lifetimes for privileged sessions.\n- No session clearing on login.\n- Storing secrets (passwords, access tokens, PII) directly in `session[...]` when using default cookie sessions.\n\nDetection hints:\n- Search for `PERMANENT_SESSION_LIFETIME`, `session.permanent`, `session[...] =`.\n- Identify whether server-side session storage is used; if not, assume default cookie sessions.\n\nFix:\n- Set appropriate lifetimes.\n- Clear/rotate session on login.\n- Store sensitive data server-side; store only identifiers in the session cookie.\n\n---\n\n### FLASK-CSRF-001: State-changing requests using cookie auth MUST be CSRF-protected\nSeverity: High\n\n- IMPORTANT NOTE: If cookies are not being used for auth (ie auth is via Authentication header or other passed token), then there is no CSRF risk.\n\nRequired:\n- MUST protect all state-changing endpoints (POST/PUT/PATCH/DELETE) that rely on cookies for authentication.\n- MAY use a well-tested CSRF library/integration (form framework or middleware) rather than rolling your own.\n- MAY use additional defenses (Origin/Referer checking, SameSite cookies, Fetch Metadata headers, custom headers for AJAX/API), but tokens remain the primary defense for cookie-authenticated apps.\nIf tokens are impractical, or for small applications:\n* MUST at a minimum require a custom header to be set and set the session cookie SESSION_COOKIE_SAMESITE=lax, as this is the strongest method besides requiring a form token, and may be much easier to implement.\n\nInsecure patterns:\n- Cookie-authenticated endpoints that change state with no CSRF protection.\n- Using GET for state-changing actions (amplifies CSRF risk).\n\nDetection hints:\n- Enumerate routes with methods other than GET and identify auth mechanism.\n- Look for CSRF integrations (e.g., Flask-WTF, global CSRF middleware). If absent, treat as suspicious.\n- Check JSON API endpoints too, not only HTML forms.\n\nFix:\n- Add CSRF protection to all state-changing requests.\n- If the app is a pure API and uses Authorization headers (bearer tokens) rather than cookies, document that choice and ensure cookies aren’t used for auth. If cookies are not used for auth, there is no CSRF risk.\n\nNotes:\n- XSS can defeat CSRF protections; CSRF defenses do not replace XSS prevention.\n\n---\n\n### FLASK-XSS-001: Prevent reflected/stored XSS in templates and HTML generation\nSeverity: High\n\nRequired:\n- MUST rely on Jinja auto-escaping for HTML templates.\n- MUST NOT mark untrusted content as safe:\n  - Avoid `Markup(...)` on user data.\n  - Avoid Jinja `|safe` on user-controlled content.\n- MUST quote HTML attributes containing Jinja expressions (`value=\"{{ x }}\"` not `value={{ x }}`).\n- MUST NOT serve uploaded HTML as active HTML; serve as download (`Content-Disposition: attachment`) or transform to a safe format. Note: This is only relevant if it is possible to upload document content such as html, js, css, etc. If it purely is image files, there is no concern.\n- SHOULD deploy a Content Security Policy (CSP) to mitigate XSS classes (including `javascript:` in `href`).\n\nInsecure patterns:\n- `Markup(request.args.get(...))`\n- Template filters: `{{ user_html|safe }}`\n- Unquoted attributes in templates\n- Serving user-uploaded content directly with `text/html` or inline rendering\n\nDetection hints:\n- Search for `Markup(` and investigate origin of the data.\n- Search template files for `|safe`, `|tojson` misuse, and unquoted attributes.\n- Review file-serving routes that might return user uploads without `as_attachment=True`. Note: This is only relevant if it is possible to upload document content such as html, js, css, etc. If it purely is image files, there is no concern.\n\nFix:\n- Remove unsafe marking; sanitize only when strictly necessary using a trusted HTML sanitizer.\n- Always quote attributes.\n- Add CSP and reduce inline scripts.\n\n---\n\n### FLASK-SSTI-001: Never render untrusted templates (Server-Side Template Injection)\nSeverity: Critical\n\nRequired:\n- MUST NOT render templates that contain user-controlled template syntax.\n- MUST treat `render_template_string` and `Environment.from_string(...).render(...)` as dangerous if the template string is influenced by untrusted input.\n- MUST NOT use use `.format()` on user controlled strings\n- If untrusted templates are absolutely required, treat it as a special high-risk design:\n  - MUST use a sandboxed templating approach and restrict capabilities.\n  - MUST keep Jinja updated and assume sandbox escapes are possible; isolate further.\n\nInsecure patterns:\n- `render_template_string(request.args[\"tmpl\"], ...)`\n- Storing user templates in DB and rendering them with the normal Jinja environment.\n- `request.args[\"tmpl\"].format(...)`\n\nDetection hints:\n- Grep for `render_template_string`, `from_string`, `.render(` with dynamic strings.\n- Trace the origin of the template string (DB, request, uploads, admin panels).\n\nFix:\n- Replace with safe templating alternatives that do not evaluate code (e.g., string.Template, str.replace).\n- If templates must be user-defined, use a sandbox plus strict allowlists and heavy isolation.\n\n---\n\n### FLASK-HEADERS-001: Set essential security headers (in app or at the edge)\nSeverity: Medium\n\nRequired (typical web app):\n- SHOULD set:\n  - CSP (`Content-Security-Policy`)\n  - `X-Content-Type-Options: nosniff`\n  - Clickjacking protection (`X-Frame-Options: SAMEORIGIN` and/or CSP `frame-ancestors`) (there may be cases where the user wants to iframe their site elsewhere. If that is the case, work with them to safely allow it)\n- SHOULD consider additional hardening headers depending on app (Referrer-Policy, Permissions-Policy).\n- MUST ensure cookies are set with secure attributes (see FLASK-SESS-001).\n\nNOTE: Security headers may be set via a proxy or other cloud provider. Check to see if there is evidence of that.\n\nInsecure patterns:\n- No security headers anywhere (app or edge).\n- CSP missing on apps that display untrusted content.\n\nDetection hints:\n- Search for `after_request` hooks, Flask-Talisman usage, reverse proxy config.\n- If not visible in app code, flag as “verify at edge”.\n\nFix:\n- Set headers centrally (middleware / after_request) or via reverse proxy/CDN.\n- Keep CSP realistic and compatible; avoid `unsafe-inline` where possible.\n\n---\n\n### FLASK-LIMITS-001: Request size and form parsing limits MUST be set appropriately\nSeverity: Low (Medium if file uploads / large bodies are possible)\n\nRequired:\n- SHOULD set and justify:\n  - `MAX_CONTENT_LENGTH` (global maximum request bytes)\n  - `MAX_FORM_MEMORY_SIZE` (max per non-file form field in multipart)\n  - `MAX_FORM_PARTS` (max number of multipart fields)\n- MUST enforce additional limits at the reverse proxy / WSGI / platform level where possible.\n\nInsecure patterns:\n- Unlimited request body sizes when handling uploads or user content.\n- Accepting arbitrarily large multipart forms or many fields.\n\nDetection hints:\n- Inspect Flask config for these keys.\n- Inspect upload routes and APIs that accept large JSON.\n\nFix:\n- Set conservative defaults, override per-route only when needed.\n- Ensure large uploads use dedicated upload mechanisms.\n\n---\n\n### FLASK-HOST-001: Host header must be validated in production\nSeverity: Low (depends on app’s use of external URLs)\n\nRequired:\n- MUST set `TRUSTED_HOSTS` in production to restrict accepted Host values.\n- MUST NOT rely on `SERVER_NAME` as a host restriction mechanism.\n\nInsecure patterns:\n- `TRUSTED_HOSTS` unset in production.\n- Code that generates external URLs for emails/password resets without host validation.\n\nDetection hints:\n- Find `TRUSTED_HOSTS` config usage.\n- Find `url_for(..., _external=True)` and check how host is determined.\n\nFix:\n- Set `TRUSTED_HOSTS` to your expected domains (and required subdomains).\n- Ensure external URL generation uses trusted host/scheme.\n\n---\n\n### FLASK-PROXY-001: Reverse proxy trust must be configured correctly\nSeverity: Medium (High if relying on IPs for auth)\n\nRequired:\n- If behind a reverse proxy, MUST configure Flask/Werkzeug to trust forwarded headers only from the intended proxy.\n- MUST NOT blindly trust `X-Forwarded-*` headers from the open internet.\n\nInsecure patterns:\n- `ProxyFix` applied with overly broad trust settings, or applied without understanding how many proxies are in front.\n- Relying on forwarded headers for scheme/host without validation.\n\nDetection hints:\n- Search for `ProxyFix`.\n- Search for usage of `request.remote_addr`, `request.scheme`, `request.host` in security-sensitive logic.\n\nFix:\n- Configure `ProxyFix` (or platform-specific settings) with correct hop counts.\n- Keep `TRUSTED_HOSTS` in place even behind proxies.\n\n---\n\n### FLASK-PATH-001: Prevent path traversal and unsafe file serving\nSeverity: High\n\nRequired:\n- MUST NOT pass user-controlled file paths to `send_file` or to direct file I/O.\n- MUST use safe file serving patterns:\n  - `send_from_directory` for user-specified paths under a trusted base directory\n  - `safe_join` for joining a trusted base directory with untrusted path components\n  - `secure_filename` for uploaded filenames (and still generate your own unique storage name)\n- MUST ensure user uploads are not served as executable/active content (especially HTML).\n- SHOULD in general use `safe_join` over `os.path.join` for almost any filesystem path computations.\n\nInsecure patterns:\n- `send_file(request.args[\"path\"])`\n- `open(os.path.join(base_dir, user_path))` where `user_path` is untrusted\n- Serving uploads from within a static web root without restrictions\n\nDetection hints:\n- Search for `send_file(`, `open(`, `os.path.join(`, `pathlib.Path(...)/...` in file routes.\n- Identify where filenames come from (request args, DB, headers).\n\nFix:\n- Serve only from a non-user-controlled directory base.\n- Store uploads outside static roots; serve through controlled routes.\n- Always validate and normalize file identifiers.\n\nNote: `safe_join` is imported from `werkzeug.security`\n\n---\n\n### FLASK-UPLOAD-001: File uploads must be validated, stored safely, and served safely\nSeverity: High\n\nRequired:\n- MUST enforce upload size limits (app + edge).\n- MUST validate file type using allowlists and content checks (not only extension).\n- MUST store uploads outside executable/static roots when possible.\n- SHOULD generate server-side filenames (random IDs) and avoid trusting original names.\n- MUST serve potentially active formats safely (download attachment) unless explicitly intended.\n\nInsecure patterns:\n- Accepting arbitrary file types and serving them back inline.\n- Using user-supplied filename as storage path.\n- Missing size/type validation.\n\nDetection hints:\n- Look for `request.files[...]` handlers.\n- Check for `secure_filename` usage (and whether it’s combined with uniqueness).\n- Check where files are stored and how they are served.\n\nFix:\n- Implement allowlist validation + safe storage + safe serving.\n- Add scanning / quarantine if applicable.\n\n---\n\n### FLASK-INJECT-001: Prevent SQL injection (use parameterized queries / ORM)\nSeverity: High\n\nRequired:\n- MUST use parameterized queries or an ORM that parameterizes under the hood.\n- MUST NOT build SQL by string concatenation / f-strings with untrusted input.\n\nInsecure patterns:\n- `f\"SELECT ... WHERE id={request.args['id']}\"`\n- `\"... WHERE name = '%s'\" % user_input`\n\nDetection hints:\n- Grep for `SELECT`, `INSERT`, `UPDATE`, `DELETE` strings in Python code.\n- Track untrusted data into DB execute calls.\n\nFix:\n- Replace with parameterized queries or ORM query APIs.\n- Validate types (e.g., int IDs) before querying.\n\n---\n\n### FLASK-INJECT-002: Prevent OS command injection\nSeverity: Critical to High (depends on exposure)\n\nRequired:\n- MUST avoid executing shell commands with untrusted input.\n- If subprocess is necessary:\n  - MUST pass args as a list (not a string)\n  - MUST NOT use `shell=True` with attacker-influenced strings\n  - SHOULD use strict allowlists for any variable component\n- If possible, use pure python or a python library rather than using a subprocess or system command\n- Do not assume that arguments to commands will be inherently safe even in `shell=False`. Commands may incorrectly process these arguments as command line flags or other trusted values.\n\nInsecure patterns:\n- `os.system(user_input)`\n- `subprocess.run(f\"cmd {user}\", shell=True)`\n- Passing user strings into `bash -c`, `sh -c`, PowerShell, etc.\n\nDetection hints:\n- Search for `os.system`, `subprocess`, `Popen`, `shell=True`.\n- Trace data from request/DB into these calls.\n\nFix:\n- Use library APIs instead of shell commands.\n- If unavoidable, hard-code the command and allowlist validated parameters. If supported by the subcommand, try to keep user values after `--` to prevent them being processed as command line flags.\n\n---\n\n### FLASK-SSRF-001: Prevent server-side request forgery (SSRF) in outbound HTTP\nSeverity: Medium\n\n- Note: For small stand alone projects this is less important. It is most important when deploying into an LAN or with other services listening on the same server.\n\nRequired:\n- MUST treat outbound requests to user-provided URLs as high risk.\n- SHOULD validate and restrict destinations (allowlist hosts/domains) for any user-influenced URL fetch.\n- SHOULD block access to:\n  - localhost / private IP ranges / link-local addresses\n  - cloud metadata endpoints\n- MUST NOT allow non http/https protocols (ie file: etc)\n- SHOULD set timeouts and restrict redirects.\n\n\n\nInsecure patterns:\n- `requests.get(request.args[\"url\"])`\n- Webhooks/preview/fetch endpoints that accept arbitrary URLs.\n\nDetection hints:\n- Search for `requests.get/post`, `httpx`, `urllib`, `aiohttp` usage with untrusted URL sources.\n- Identify URL fetch features (preview, import, webhook tester).\n\nFix:\n- Ensure URLs are http or https (disallow file: or other protocols)\n- Enforce allowlists and network egress controls.\n- Add strict parsing and IP resolution checks; set timeouts; disable redirects if not needed.\n\n---\n\n### FLASK-REDIRECT-001: Prevent open redirects\nSeverity: Low\n\nRequired:\n- MUST validate redirect targets derived from untrusted input (e.g., `next`, `redirect`, `return_to`).\n- SHOULD use allowlists of internal paths or known domains.\n- SHOULD prefer redirecting only to same-site relative paths.\n\nInsecure patterns:\n- `redirect(request.args.get(\"next\"))` with no validation.\n\nDetection hints:\n- Search for `redirect(` and examine where `location` comes from.\n\nFix:\n- Only allow relative paths or allowlisted domains.\n- Fall back to a safe default if validation fails.\n\n---\n\n### FLASK-HTTP-001: Use HTTP methods safely; do not change state via GET; avoid secrets in URLs\nSeverity: Medium\n\nRequired:\n- MUST NOT perform state-changing actions over GET.\n- MUST NOT put secrets in URLs (query strings are commonly logged and leaked via referrers).\n- SHOULD require POST/PUT/PATCH/DELETE for state change and apply CSRF protections when cookie-authenticated.\n\nInsecure patterns:\n- `/delete?id=...` implemented as GET\n- Password reset tokens or API keys in query params\n\nDetection hints:\n- Enumerate GET routes and inspect whether they mutate state.\n- Look for URL parameters named `token`, `key`, `secret`, `password`, etc.\n\nFix:\n- Move state changes to non-GET methods.\n- Move sensitive values to secure channels (POST bodies, headers) and protect them.\n\n---\n\n### FLASK-CORS-001: CORS must be explicit and least-privilege\nSeverity: Medium (High if misconfigured with credentials)\n\nRequired:\n- If CORS is not needed, MUST keep it disabled.\n- If CORS is needed:\n  - MUST allowlist trusted origins (do not reflect arbitrary origins).\n  - MUST be careful with credentialed requests; do not combine broad origins with cookies.\n  - SHOULD restrict allowed methods and headers.\n\nInsecure patterns:\n- `Access-Control-Allow-Origin: *` paired with credentialed cookies or overly broad access.\n- Reflecting `Origin` without validation.\n- `flask_cors.CORS(app)` with permissive defaults.\n\nDetection hints:\n- Search for `flask_cors`, `CORS(`, `Access-Control-Allow-Origin`.\n- Check for `supports_credentials=True` and wildcard origins.\n\nFix:\n- Use a strict origin allowlist and minimal methods/headers.\n- Ensure cookie-authenticated endpoints are not exposed cross-origin unless necessary.\n\n---\n\n### FLASK-SUPPLY-001: Dependency and patch hygiene (focus on security-relevant deps)\nSeverity: Low\n\nRequired:\n- SHOULD pin and regularly update security-critical dependencies (Flask, Werkzeug, Jinja2, itsdangerous).\n- MUST respond to known security advisories promptly.\n\nAudit focus example:\n- If running on Windows and using file serving with untrusted paths, ensure Werkzeug’s `safe_join` behavior is not vulnerable to Windows device-name edge cases.\n\nDetection hints:\n- Check `requirements.txt`, lockfiles, and runtime environments.\n- Identify where security helpers are used (safe_join, send_from_directory).\n\nFix:\n- Upgrade to patched versions and add regression tests for the impacted behavior.\n\n--------------------------------------------------------------------\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n- Dev server / debug:\n  - `app.run(`, `flask run`, `--debug`, `DEBUG=True`, `FLASK_DEBUG`\n- Secrets:\n  - `SECRET_KEY`, `secret_key`, `.env` committed, `print(config)`\n- Cookies / sessions:\n  - `SESSION_COOKIE_SECURE`, `SESSION_COOKIE_HTTPONLY`, `SESSION_COOKIE_SAMESITE`\n  - `session[...] =` with sensitive values\n- CSRF:\n  - POST/PUT/PATCH/DELETE handlers without CSRF checks in cookie-authenticated apps\n- XSS/SSTI:\n  - `Markup(`, `|safe`, unquoted attributes, `render_template_string`\n- Files:\n  - `send_file(` with user-controlled path; `open(` on user path; `os.path.join` with untrusted\n  - upload handlers using user filename for path\n- Injection:\n  - SQL strings + string formatting into `.execute(...)`\n  - `subprocess.*`, `shell=True`, `os.system`\n- SSRF:\n  - `requests.get/post` or `httpx` with URL from request/DB\n- Redirect:\n  - `redirect(request.args.get(\"next\"))`\n- CORS:\n  - `flask_cors.CORS` permissive configs; wildcard origins with credentials\n\nAlways try to confirm:\n- data origin (untrusted vs trusted)\n- sink type (template/SQL/subprocess/files/redirect/http)\n- protective controls present (validation, allowlists, middleware)\n\n--------------------------------------------------------------------\n\n## 6) Sources (accessed 2026-01-26)\n\nPrimary framework documentation:\n- Flask Docs: Deploying to Production — https://flask.palletsprojects.com/en/stable/deploying/\n- Flask Docs: Debugging Application Errors — https://flask.palletsprojects.com/en/stable/debugging/\n- Flask Docs: Configuration Handling — https://flask.palletsprojects.com/en/stable/config/\n- Flask Docs: Security Considerations — https://flask.palletsprojects.com/en/stable/web-security/\n- Flask Docs: Tell Flask it is Behind a Proxy — https://flask.palletsprojects.com/en/stable/deploying/proxy_fix/\n- Flask API Docs: Sessions — https://flask.palletsprojects.com/en/stable/api/#sessions\n\nWerkzeug documentation & advisories:\n- Werkzeug Docs: Utilities (send_file / send_from_directory / safe_join / secure_filename / password hashing) — https://werkzeug.palletsprojects.com/en/stable/utils/\n- GitHub Advisory: CVE-2025-66221 (Werkzeug safe_join Windows device names) — https://github.com/advisories/GHSA-hgf8-39gv-g3f2\n\nOWASP Cheat Sheet Series:\n- Session Management — https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html\n- CSRF Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html\n- XSS Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html\n- Input Validation — https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html\n- SQL Injection Prevention — https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html\n- Injection Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Injection_Prevention_Cheat_Sheet.html\n- OS Command Injection Defense — https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html\n- SSRF Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html\n- File Upload — https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html\n- Unvalidated Redirects — https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html\n- HTTP Headers — https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html\n\nTemplate safety references:\n- Jinja: Sandbox (rendering untrusted templates) — https://jinja.palletsprojects.com/en/stable/sandbox/\n- OWASP WSTG: Testing for Server-Side Template Injection — https://owasp.org/www-project-web-security-testing-guide/v41/4-Web_Application_Security_Testing/07-Input_Validation_Testing/18-Testing_for_Server_Side_Template_Injection\n- PortSwigger Web Security Academy: Server-side template injection — https://portswigger.net/web-security/server-side-template-injection\n\nHTTP semantics:\n- RFC 9110: HTTP Semantics (safe methods) — https://www.rfc-editor.org/rfc/rfc9110\n","isInternal":false,"tokens":7077,"sizeBytes":31749},{"name":"SKILL.md","path":"core/skills/builtin/security-best-practices/SKILL.md","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/security-best-practices/SKILL.md","title":"security-best-practices","category":"anthropic-skill","format":"markdown","content":"---\nname: \"security-best-practices\"\ndescription: \"Perform language and framework specific security best-practice reviews and suggest improvements. Trigger only when the user explicitly requests security best practices guidance, a security review/report, or secure-by-default coding help. Trigger only for supported languages (python, javascript/typescript, go). Do not trigger for general code review, debugging, or non-security tasks.\"\n---\n\n# Security Best Practices\n\n## Overview\n\nThis skill provides a description of how to identify the language and frameworks used by the current context, and then to load information from this skill's references directory about the security best practices for this language and or frameworks.\n\nThis information, if present, can be used to write new secure by default code, or to passively detect major issues within existing code, or (if requested by the user) provide a vulnerability report and suggest fixes.\n\n## Workflow\n\nThe initial step for this skill is to identify ALL languages and ALL frameworks which you are being asked to use or already exist in the scope of the project you are working in. Focus on the primary core frameworks. Often you will want to identify both frontend and backend languages and frameworks.\n\nThen check this skill's references directory to see if there are any relevant documentation for the language and or frameworks. Make sure you read ALL reference files which relate to the specific framework or language. The format of the filenames is `<language>-<framework>-<stack>-security.md`. You should also check if there is a `<language>-general-<stack>-security.md` which is agnostic to the framework you may be using.\n\nIf working on a web application which includes a frontend and a backend, make sure you have checked for reference documents for BOTH the frontend and backend!\n\nIf you are asked to make a web app which will include both a frontend and backend, but the frontend framework is not specified, also check out `javascript-general-web-frontend-security.md`. It is important that you understand how to secure both the frontend and backend.\n\nIf no relevant information is available in the skill's references directory, think a little bit about what you know about the language, the framework, and all well known security best practices for it. If you are unsure you can try to search online for documentation on security best practices.\n\nFrom there it can operate in a few ways.\n\n1. The primary mode is to just use the information to write secure by default code from this point forward. This is useful for starting a new project or when writing new code.\n\n2. The secondary mode is to passively detect vulnerabilities while working in the project and writing code for the user. Critical or very important vulnerabilities or major issues going against security guidance can be flagged and the user can be told about them. This passive mode should focus on the largest impact vulnerabilities and secure defaults.\n\n3. The user can ask for a security report or to improve the security of the codebase. In this case a full report should be produced describe anyways the project fails to follow security best practices guidance. The report should be prioritized and have clear sections of severity and urgency. Then offer to start working on fixes for these issues. See #fixes below.\n\n## Workflow Decision Tree\n\n- If the language/framework is unclear, inspect the repo to determine it and list your evidence.\n- If matching guidance exists in `references/`, load only the relevant files and follow their instructions.\n- If no matching guidance exists, consider if you know any well known security best practices for the chosen language and or frameworks, but if asked to generate a report, let the user know that concrete guidance is not available (you can still generate the report or detect for sure critical vulnerabilities)\n\n# Overrides\n\nWhile these references contain the security best practices for languages and frameworks, customers may have cases where they need to bypass or override these practices. Pay attention to specific rules and instructions in the project's documentation and prompt files which may require you to override certain best practices. When overriding a best practice, you MAY report it to the user, but do not fight with them. If a security best practice needs to be bypassed / ignored for some project specific reason, you can also suggest to add documentation about this to the project so it is clear why the best practice is not being followed and to follow that bypass in the future.\n\n# Report Format\n\nWhen producing a report, you should write the report as a markdown file in `security_best_practices_report.md` or some other location if provided by the user. You can ask the user where they would like the report to be written to.\n\nThe report should have a short executive summary at the top.\n\nThe report should be clearly delineated into multiple sections based on severity of the vulnerability. The report should focus on the most critical findings as these have the highest impact for the user. All findings should be noted with an numeric ID to make them easier to reference.\n\nFor critical findings include a one sentence impact statement.\n\nOnce the report is written, also report it to the user directly, although you may be less verbose. You can offer to explain any of the findings or the reasons behind the security best practices guidance if the user wants more info on any findings.\n\nImportant: When referencing code in the report, make sure to find and include line numbers for the code you are referencing.\n\nAfter you write the report file, summarize the findings to the user.\n\nAlso tell the user where the final report was written to\n\n# Fixes\n\nIf you produced a report, let the user read the report and ask to begin performing fixes.\n\nIf you passively found a critical finding, notify the user and ask if they would like you to fix this finding.\n\nWhen producing fixes, focus on fixing a single finding at a time. The fixes should have concise clear comments explaining that the new code is based on the specific security best practice, and perhaps a very short reason why it would be dangerous to not do it in this way.\n\nAlways consider if the changes you want to make will impact the functionality of the user's code. Consider if the changes may cause regressions with how the project works currently. It is often the case that insecure code is relied on for other reasons (and this is why insecure code lives on for so long). Avoid breaking the user's project as this may make them not want to apply security fixes in the future. It is better to write a well thought out, well informed by the rest of the project, fix, then a quick slapdash change.\n\nAlways follow any normal change or commit flow the user has configured. If making git commits, provide clear commit messages explaining this is to align with security best practices. Try to avoid bunching a number of unrelated findings into a single commit.\n\nAlways follow any normal testing flows the user has configured (if any) to confirm that your changes are not introducing regressions. Consider the second order impacts the changes may have and inform the user before making them if there are any.\n\n# General Security Advice\n\nBelow is a few bits of secure coding advice that applies to almost any language or framework.\n\n### Avoid Using Incrementing IDs for Public IDs of Resources\n\nWhen assigning an ID for some resource, which will then be used by exposed to the internet, avoid using small auto-incrementing IDs. Use longer, random UUID4 or random hex string instead. This will prevent users from learning the quantity of a resource and being able to guess resource IDs.\n\n### A note on TLS\n\nWhile TLS is important for production deployments, most development work will be with TLS disabled or provided by some out-of-scope TLS proxy. Due to this, be very careful about not reporting lack of TLS as a security issue. Also be very careful around use of \"secure\" cookies. They should only be set if the application will actually be over TLS. If they are set on non-TLS applications (such as when deployed for local dev or testing), it will break the application. You can provide a env or other flag to override setting secure as a way to keep it off until on a TLS production deployment. Additionally avoid recommending HSTS. It is dangerous to use without full understanding of the lasting impacts (can cause major outages and user lockout) and it is not generally recommended for the scope of projects being reviewed by codex.\n","frontmatter":{"name":"security-best-practices","description":"Perform language and framework specific security best-practice reviews and suggest improvements. Trigger only when the user explicitly requests security best practices guidance, a security review/report, or secure-by-default coding help. Trigger only for supported languages (python, javascript/typescript, go). Do not trigger for general code review, debugging, or non-security tasks."},"isInternal":false,"tokens":1663,"sizeBytes":8612},{"name":"openai.yaml","path":"core/skills/builtin/security-ownership-map/agents/openai.yaml","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/security-ownership-map/agents/openai.yaml","title":"Agents Skill","category":"anthropic-skill","format":"yaml","content":"interface:\n  display_name: \"Security Ownership Map\"\n  short_description: \"Map maintainers, bus factor, and sensitive code ownership\"\n  default_prompt: \"Build a security ownership map for this repository and identify bus-factor risks in sensitive code.\"\n","isInternal":false,"tokens":50,"sizeBytes":253},{"name":"neo4j-import.md","path":"core/skills/builtin/security-ownership-map/references/neo4j-import.md","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/security-ownership-map/references/neo4j-import.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Neo4j Import Notes\n\nUse these steps when persisting the ownership graph to Neo4j.\n\n## Quick import (LOAD CSV)\n\n1. Copy `people.csv`, `files.csv`, and `edges.csv` into the Neo4j import directory.\n2. Run the following Cypher from Neo4j Browser or `cypher-shell`:\n\n```cypher\nCREATE CONSTRAINT person_id IF NOT EXISTS FOR (p:Person) REQUIRE p.id IS UNIQUE;\nCREATE CONSTRAINT file_id IF NOT EXISTS FOR (f:File) REQUIRE f.id IS UNIQUE;\n\nLOAD CSV WITH HEADERS FROM 'file:///people.csv' AS row\nMERGE (p:Person {id: row.person_id})\nSET p.name = row.name,\n    p.email = row.email,\n    p.first_seen = row.first_seen,\n    p.last_seen = row.last_seen,\n    p.commit_count = toInteger(row.commit_count),\n    p.touches = toInteger(row.touches),\n    p.sensitive_touches = toFloat(row.sensitive_touches),\n    p.primary_tz_offset = CASE row.primary_tz_offset WHEN '' THEN null ELSE row.primary_tz_offset END,\n    p.primary_tz_minutes = CASE row.primary_tz_minutes WHEN '' THEN null ELSE toInteger(row.primary_tz_minutes) END,\n    p.timezone_offsets = CASE row.timezone_offsets WHEN '' THEN null ELSE row.timezone_offsets END;\n\nLOAD CSV WITH HEADERS FROM 'file:///files.csv' AS row\nMERGE (f:File {id: row.file_id})\nSET f.path = row.path,\n    f.first_seen = row.first_seen,\n    f.last_seen = row.last_seen,\n    f.commit_count = toInteger(row.commit_count),\n    f.touches = toInteger(row.touches),\n    f.bus_factor = toInteger(row.bus_factor),\n    f.sensitivity_score = toFloat(row.sensitivity_score),\n    f.sensitivity_tags = row.sensitivity_tags;\n\nLOAD CSV WITH HEADERS FROM 'file:///edges.csv' AS row\nMATCH (p:Person {id: row.person_id})\nMATCH (f:File {id: row.file_id})\nMERGE (p)-[r:TOUCHES]->(f)\nSET r.touches = toInteger(row.touches),\n    r.recency_weight = toFloat(row.recency_weight),\n    r.first_seen = row.first_seen,\n    r.last_seen = row.last_seen,\n    r.sensitive_weight = toFloat(row.sensitive_weight);\n\nLOAD CSV WITH HEADERS FROM 'file:///cochange_edges.csv' AS row\nMATCH (f1:File {id: row.file_a})\nMATCH (f2:File {id: row.file_b})\nMERGE (f1)-[r:COCHANGES]->(f2)\nSET r.cochange_count = toInteger(row.cochange_count),\n    r.jaccard = toFloat(row.jaccard);\n```\n\n## Visualization tips\n\n- Use Neo4j Bloom or Browser with `MATCH (p:Person)-[r:TOUCHES]->(f:File) RETURN p,r,f`.\n- Filter by `f.sensitivity_score > 0` to highlight security-relevant clusters.\n- For Gephi, import `edges.csv` as edges and `files.csv` / `people.csv` as nodes.\n","isInternal":false,"tokens":665,"sizeBytes":2428},{"name":"SKILL.md","path":"core/skills/builtin/security-ownership-map/SKILL.md","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/security-ownership-map/SKILL.md","title":"security-ownership-map","category":"anthropic-skill","format":"markdown","content":"---\nname: \"security-ownership-map\"\ndescription: \"Analyze git repositories to build a security ownership topology (people-to-file), compute bus factor and sensitive-code ownership, and export CSV/JSON for graph databases and visualization. Trigger only when the user explicitly wants a security-oriented ownership or bus-factor analysis grounded in git history (for example: orphaned sensitive code, security maintainers, CODEOWNERS reality checks for risk, sensitive hotspots, or ownership clusters). Do not trigger for general maintainer lists or non-security ownership questions.\"\n---\n\n# Security Ownership Map\n\n## Overview\n\nBuild a bipartite graph of people and files from git history, then compute ownership risk and export graph artifacts for Neo4j/Gephi. Also build a file co-change graph (Jaccard similarity on shared commits) to cluster files by how they move together while ignoring large, noisy commits.\n\n## Requirements\n\n- Python 3\n- `networkx` (required; community detection is enabled by default)\n\nInstall with:\n\n```bash\npip install networkx\n```\n\n## Workflow\n\n1. Scope the repo and time window (optional `--since/--until`).\n2. Decide sensitivity rules (use defaults or provide a CSV config).\n3. Build the ownership map with `scripts/run_ownership_map.py` (co-change graph is on by default; use `--cochange-max-files` to ignore supernode commits).\n4. Communities are computed by default; graphml output is optional (`--graphml`).\n5. Query the outputs with `scripts/query_ownership.py` for bounded JSON slices.\n6. Persist and visualize (see `references/neo4j-import.md`).\n\nBy default, the co-change graph ignores common “glue” files (lockfiles, `.github/*`, editor config) so clusters reflect actual code movement instead of shared infra edits. Override with `--cochange-exclude` or `--no-default-cochange-excludes`. Dependabot commits are excluded by default; override with `--no-default-author-excludes` or add patterns via `--author-exclude-regex`.\n\nIf you want to exclude Linux build glue like `Kbuild` from co-change clustering, pass:\n\n```bash\npython skills/skills/security-ownership-map/scripts/run_ownership_map.py \\\n  --repo /path/to/linux \\\n  --out ownership-map-out \\\n  --cochange-exclude \"**/Kbuild\"\n```\n\n## Quick start\n\nRun from the repo root:\n\n```bash\npython skills/skills/security-ownership-map/scripts/run_ownership_map.py \\\n  --repo . \\\n  --out ownership-map-out \\\n  --since \"12 months ago\" \\\n  --emit-commits\n```\n\nDefaults: author identity, author date, and merge commits excluded. Use `--identity committer`, `--date-field committer`, or `--include-merges` if needed.\n\nExample (override co-change excludes):\n\n```bash\npython skills/skills/security-ownership-map/scripts/run_ownership_map.py \\\n  --repo . \\\n  --out ownership-map-out \\\n  --cochange-exclude \"**/Cargo.lock\" \\\n  --cochange-exclude \"**/.github/**\" \\\n  --no-default-cochange-excludes\n```\n\nCommunities are computed by default. To disable:\n\n```bash\npython skills/skills/security-ownership-map/scripts/run_ownership_map.py \\\n  --repo . \\\n  --out ownership-map-out \\\n  --no-communities\n```\n\n## Sensitivity rules\n\nBy default, the script flags common auth/crypto/secret paths. Override by providing a CSV file:\n\n```\n# pattern,tag,weight\n**/auth/**,auth,1.0\n**/crypto/**,crypto,1.0\n**/*.pem,secrets,1.0\n```\n\nUse it with `--sensitive-config path/to/sensitive.csv`.\n\n## Output artifacts\n\n`ownership-map-out/` contains:\n\n- `people.csv` (nodes: people)\n- `files.csv` (nodes: files)\n- `edges.csv` (edges: touches)\n- `cochange_edges.csv` (file-to-file co-change edges with Jaccard weight; omitted with `--no-cochange`)\n- `summary.json` (security ownership findings)\n- `commits.jsonl` (optional, if `--emit-commits`)\n- `communities.json` (computed by default from co-change edges when available; includes `maintainers` per community; disable with `--no-communities`)\n- `cochange.graph.json` (NetworkX node-link JSON with `community_id` + `community_maintainers`; falls back to `ownership.graph.json` if no co-change edges)\n- `ownership.graphml` / `cochange.graphml` (optional, if `--graphml`)\n\n`people.csv` includes timezone detection based on author commit offsets: `primary_tz_offset`, `primary_tz_minutes`, and `timezone_offsets`.\n\n## LLM query helper\n\nUse `scripts/query_ownership.py` to return small, JSON-bounded slices without loading the full graph into context.\n\nExamples:\n\n```bash\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out people --limit 10\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out files --tag auth --bus-factor-max 1\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out person --person alice@corp --limit 10\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out file --file crypto/tls\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out cochange --file crypto/tls --limit 10\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out summary --section orphaned_sensitive_code\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out community --id 3\n```\n\nUse `--community-top-owners 5` (default) to control how many maintainers are stored per community.\n\n## Basic security queries\n\nRun these to answer common security ownership questions with bounded output:\n\n```bash\n# Orphaned sensitive code (stale + low bus factor)\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out summary --section orphaned_sensitive_code\n\n# Hidden owners for sensitive tags\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out summary --section hidden_owners\n\n# Sensitive hotspots with low bus factor\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out summary --section bus_factor_hotspots\n\n# Auth/crypto files with bus factor <= 1\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out files --tag auth --bus-factor-max 1\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out files --tag crypto --bus-factor-max 1\n\n# Who is touching sensitive code the most\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out people --sort sensitive_touches --limit 10\n\n# Co-change neighbors (cluster hints for ownership drift)\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out cochange --file path/to/file --min-jaccard 0.05 --limit 20\n\n# Community maintainers (for a cluster)\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out community --id 3\n\n# Monthly maintainers for the community containing a file\npython skills/skills/security-ownership-map/scripts/community_maintainers.py \\\n  --data-dir ownership-map-out \\\n  --file network/card.c \\\n  --since 2025-01-01 \\\n  --top 5\n\n# Quarterly buckets instead of monthly\npython skills/skills/security-ownership-map/scripts/community_maintainers.py \\\n  --data-dir ownership-map-out \\\n  --file network/card.c \\\n  --since 2025-01-01 \\\n  --bucket quarter \\\n  --top 5\n```\n\nNotes:\n- Touches default to one authored commit (not per-file). Use `--touch-mode file` to count per-file touches.\n- Use `--window-days 90` or `--weight recency --half-life-days 180` to smooth churn.\n- Filter bots with `--ignore-author-regex '(bot|dependabot)'`.\n- Use `--min-share 0.1` to show stable maintainers only.\n- Use `--bucket quarter` for calendar quarter groupings.\n- Use `--identity committer` or `--date-field committer` to switch from author attribution.\n- Use `--include-merges` to include merge commits (excluded by default).\n\n### Summary format (default)\n\nUse this structure, add fields if needed:\n\n```json\n{\n  \"orphaned_sensitive_code\": [\n    {\n      \"path\": \"crypto/tls/handshake.rs\",\n      \"last_security_touch\": \"2023-03-12T18:10:04+00:00\",\n      \"bus_factor\": 1\n    }\n  ],\n  \"hidden_owners\": [\n    {\n      \"person\": \"alice@corp\",\n      \"controls\": \"63% of auth code\"\n    }\n  ]\n}\n```\n\n## Graph persistence\n\nUse `references/neo4j-import.md` when you need to load the CSVs into Neo4j. It includes constraints, import Cypher, and visualization tips.\n\n## Notes\n\n- `bus_factor_hotspots` in `summary.json` lists sensitive files with low bus factor; `orphaned_sensitive_code` is the stale subset.\n- If `git log` is too large, narrow with `--since` or `--until`.\n- Compare `summary.json` against CODEOWNERS to highlight ownership drift.\n","frontmatter":{"name":"security-ownership-map","description":"Analyze git repositories to build a security ownership topology (people-to-file), compute bus factor and sensitive-code ownership, and export CSV/JSON for graph databases and visualization. Trigger only when the user explicitly wants a security-oriented ownership or bus-factor analysis grounded in git history (for example: orphaned sensitive code, security maintainers, CODEOWNERS reality checks for risk, sensitive hotspots, or ownership clusters). Do not trigger for general maintainer lists or non-security ownership questions."},"isInternal":false,"tokens":2083,"sizeBytes":8736},{"name":"openai.yaml","path":"core/skills/builtin/security-threat-model/agents/openai.yaml","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/security-threat-model/agents/openai.yaml","title":"Agents Skill","category":"anthropic-skill","format":"yaml","content":"interface:\n  display_name: \"Security Threat Model\"\n  short_description: \"Repo-grounded threat modeling and abuse-path analysis\"\n  default_prompt: \"Create a repository-grounded threat model for this codebase with prioritized abuse paths and mitigations.\"\n","isInternal":false,"tokens":51,"sizeBytes":254},{"name":"prompt-template.md","path":"core/skills/builtin/security-threat-model/references/prompt-template.md","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/security-threat-model/references/prompt-template.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Threat Modeling Prompt Template for LLMs\n\nThis reference provides a disciplined, repo-grounded prompt that produces AppSec-usable threat models. Use it when you need a reliable output contract and a consistent process to assemble the threat model output\n\n## System prompt\n\nUse this as a stable system prompt:\n\n````text\nYou are a senior application security engineer producing a threat model that will be read by other AppSec engineers.\n\nPrimary objective:\n- Generate a threat model that is specific to THIS repository and its real-world usage.\n- Prefer concrete, evidence-backed findings over generic vulnerability checklists.\n\nEvidence and grounding rules:\n- Do not invent components, data stores, endpoints, flows, or controls.\n- Every architectural claim must be backed by at least one \"Evidence anchor\" referencing a repo path\n  (and a symbol name, config key, or a short quoted snippet if available).\n- If information is missing, state assumptions explicitly and list the open questions needed to validate them.\n\nSecurity hygiene:\n- Never output secrets. If you encounter tokens/keys/passwords, redact them and only describe their presence and location.\n\nThreat modeling approach:\n- Model the system using data flows and trust boundaries.\n- Enumerate threats and produce attack goals and abuse paths\n- Prioritize threats using explicit likelihood and impact reasoning (qualitative is acceptable: low/medium/high).\n\nScope discipline:\n- Clearly separate: production/runtime behavior vs CI/build/dev tooling vs tests/examples.\n- Clearly separate attacker-controlled inputs vs operator-controlled inputs vs developer-controlled inputs.\n- If a vulnerability class requires attacker control that likely does not exist for this repo's real usage, say so and downgrade severity.\n\nCommunication quality:\n- Write for AppSec engineers: concise but specific.\n- Use precise terminology. Include mitigations and residual risks.\n- Avoid restating large blocks of README/spec; summarize and point to evidence.\n\nDiagram requirements:\n- Produce a single compact Mermaid flowchart showing primary components and trust boundaries.\n- Mermaid must render cleanly. Use a conservative subset:\n  - Use `flowchart TD` or `flowchart LR` and only `-->` arrows.\n  - Use simple node IDs (letters/numbers/underscores only) and quoted labels (e.g., `A[\"Label\"]`); avoid `A(Label)` shape syntax.\n  - Do not use Mermaid `title` lines or `style` directives.\n  - Keep edge labels to plain words/spaces only via `-->|label|`; avoid `{}`, `[]`, `()`, or quotes in edge labels (if needed, drop the label).\n  - Keep node labels short and readable: do not include file paths, URLs, or socket paths (put those details in prose outside the diagram).\n- Wrap the diagram in a Markdown fenced block:\n  ```mermaid\n  <mermaid syntax here>\n  ```\n````\n\n## Repository summary prompt\n\n```\nWe have a codebase located at {repo_directory/path}, currently on branch {branch_name}.\n\nPlease produce a security-oriented summary of the repository (or the specified sub-path) with the goal of helping a follow-on security engineer quickly understand the system well enough to build an initial threat model and investigate potential security hypotheses.\n\nObjectives\n1.\tProject overview\n\t•\tIdentify the primary programming languages, frameworks, and build system.\n\t•\tSummarize the project’s core purpose and high-level architecture.\n\t•\tDescribe major components, services, or modules and how they interact.\n2.\tSecurity posture and entry points\n\t•\tIdentify likely user entry points and trust boundaries.\n\t•\tDescribe existing security layers (e.g., authentication, authorization, validation, sandboxing, isolation, privilege boundaries).\n\t•\tCall out security-critical components and assumptions that must hold for the system to remain secure.\n\nGuidance for Security Analysis\n\nStructure the summary so an application security engineer can quickly answer questions such as:\n\t•\tWhere does user input originate?\n\t•\tHow is untrusted data parsed, validated, and handled?\n\t•\tWhat security assumptions should not be violated?\n\t•\tWhere are the most likely choke points for security bugs?\n\nAdapt the analysis to the project type. For example:\n\t•\tWeb applications: where requests enter, how user data is parsed, routed, authenticated, and stored.\n\t•\tCommand-line tools: supported inputs (arguments, files, environment variables, stdin) and how they are processed.\n\t•\tNetwork daemons: exposed ports, supported protocols, message formats, and request handling paths.\n\t•\tOperating system or low-level components: common vulnerability classes (e.g., memory corruption, logic flaws) that could lead to LPE or RCE.\n\nBe thorough but pragmatic: the goal is to help a security engineer quickly determine whether a discovered bug is security-relevant and where deeper investigation should focus.\n\nTooling Notes\n\nIf Ripgrep (rg) is available, use it to explore the codebase. When using grep or rg, always include the -I flag to avoid searching through binary files.\n```\n\n\n\n## User prompt template\n\nUse this as the task prompt, filling in what you know and marking the rest as assumptions:\n\n```text\n# Inputs\nContext (fill as available; otherwise infer and mark assumptions):\n- intended_usage: {intended_usage}\n- deployment_model: {deployment_model}\n- data_sensitivity: {data_sensitivity}\n- internet_exposure: {internet_exposure}\n- authn_authz_expectations: {authn_authz_expectations}\n- out_of_scope: {out_of_scope}\n\nProvided summaries (may be incomplete):\n- repository_summary: {repository_summary}\n\n\nIn-scope code locations (if known):\n- in_scope_paths: {in_scope_paths}\n\n# Task\nConstruct a repo-centric threat model that helps AppSec engineers understand the most important security risks and where to focus manual review.\n\nYou MUST follow this process and reflect outputs in the final document:\n\n## Process\n1) Repo discovery (evidence collection)\n   a. Identify the repo shape:\n      - languages and frameworks\n      - how it runs (server/cli/library), entrypoints, build artifacts\n   b. Identify security-relevant surfaces and controls by searching for evidences, such as:\n      - network listeners/routes/endpoints; RPC handlers; message consumers\n      - authentication, session/token handling, authorization checks, RBAC/ACL logic\n      - parsing/serialization/deserialization (JSON/YAML/XML/protobuf), template rendering, eval/dynamic code\n      - file upload/read paths, archive extraction, image/document parsing\n      - database/queue/cache clients and query construction\n      - secrets/config loading, environment variables, key management\n      - SSRF-capable HTTP clients, webhooks, URL fetchers\n      - sandboxing/isolation, privilege boundaries, subprocess execution\n      - logging/auditing and error handling paths\n      - CI/build/release: pipelines, dependency management, artifact publishing\n\n2) System model\n   a. Summarize the primary components (runtime plus critical build/CI components when relevant).\n   b. Enumerate data flows and trust boundaries.\n      - For each trust boundary, specify:\n        * source to destination\n        * data types crossing (e.g., credentials, PII, files, tokens, prompts)\n        * channel/protocol (HTTP/gRPC/IPC/file/db)\n        * security guarantees and validation (auth, mTLS, origin checks, schema validation, rate limits)\n   c. Provide a compact Mermaid diagram showing components and trust boundaries.\n\n3) Assets and security objectives\n   - List assets (data, credentials, integrity-critical state, availability-critical components, build artifacts).\n   - For each asset, state why it matters (confidentiality/integrity/availability, compliance, user harm).\n\n4) Attacker model\n   - Capabilities: realistic remote attacker assumptions based on intended usage and exposure.\n   - Non-capabilities: things attacker cannot plausibly do (unless explicitly in scope), to avoid inflated severity.\n\n5) Threat enumeration (concrete, system-specific)\n   - Generate threats as attacker stories tied to:\n     * entry points\n     * trust boundaries\n     * privileged components\n   - Prefer abuse paths (multi-step sequences) over single-line generic threats.\n\n6) Risk prioritization\n   - For each threat:\n     * Likelihood: low/medium/high with a 1 to 2 sentence justification\n     * Impact: low/medium/high with a 1 to 2 sentence justification\n     * Overall priority: critical/high/medium/low (based on likelihood x impact, adjusted for existing controls)\n   - Explicitly state which assumptions most affect risk.\n\n7) Validate assumptions and service context with the user (required before final report)\n   - Summarize key assumptions that materially affect scope or risk ranking.\n   - Ask 1 to 3 targeted questions to resolve missing service meta-context (service owner/environment, scale/users, deployment model, authn/authz, internet exposure, data sensitivity, multi-tenancy).\n   - Pause and wait for user feedback before producing the final report.\n   - If the user cannot answer, proceed with explicit assumptions and mark any conditional conclusions.\n\n8) Mitigations and recommendations\n   - For each high/critical threat:\n     * Existing mitigations (with evidence anchors)\n     * Gaps/weaknesses\n     * Recommended mitigations (code/config/process)\n     * Detection/monitoring ideas (logging, metrics, alerts)\n\n9) Focus paths for manual security review\n   - Output 2 to 30 repo-relative paths (files or directories) that merit deeper review.\n   - For each path, give a one-sentence reason tied to the threat model.\n\n10) Quality check\n   - Provide a short checklist confirming you covered:\n     * all entry points you discovered\n     * each trust boundary at least once in threats\n     * runtime vs CI/dev separation\n     * user clarifications (or explicit non-responses)\n     * assumptions and open questions\n\n## Required output format (exact)\nBefore producing the final Markdown report, first provide an assumption-validation check-in:\n- List the key assumptions in 3 to 6 bullets.\n- Ask 1 to 3 targeted context questions.\n- Wait for the user response, then produce the final report below using the clarified context.\n\nProduce valid Markdown with these sections in this order:\n\n## Executive summary\n- 1 short paragraph on the top risk themes and highest-risk areas.\n\n## Scope and assumptions\n- In-scope paths, out-of-scope items, and explicit assumptions.\n- A short list of open questions that would materially change the risk ranking.\n\n\n## System model\n### Primary components\n### Data flows and trust boundaries\nRepresent the system as a sequence of arrow-style bullets (e.g., Internet → API Server, User Input -> Application Logic, etc). For each boundary, document:\n\t•\tthe primary data types crossing the boundary,\n\t•\tthe communication channel or protocol,\n\t•\tthe security guarantees (e.g., authentication, origin checks, encryption, rate limiting), and\n\t•\tany input validation, normalization, or schema enforcement performed.\n\n#### Diagram\n- Include a single, compact Mermaid diagram (`flowchart TD` or `flowchart LR`) showing primary components and trust boundaries (e.g., separate trust zones via subgraphs). Keep it compact, use only `-->`, avoid `title`/`style`, keep node labels short (no paths/URLs), and keep edge labels to plain words only (avoid `{}`, `[]`, `()`, or quotes).\n\n\n## Assets and security objectives\n- A table: Asset | Why it matters | Security objective (C/I/A)\n\n## Attacker model\n### Capabilities\n### Non-capabilities\n\n## Entry points and attack surfaces\n- A table: Surface | How reached | Trust boundary | Notes | Evidence (repo path / symbol)\n\n## Top abuse paths\n- 5 to 10 short abuse paths, each as a numbered sequence of steps (attacker goal -> steps -> impact).\n\n## Threat model table\n- A Markdown table with columns:\n  Threat ID | Threat source | Prerequisites | Threat action | Impact | Impacted assets | Existing controls (evidence) | Gaps | Recommended mitigations | Detection ideas | Likelihood | Impact severity | Priority\n\nRules:\n- Threat IDs must be stable and formatted: TM-001, TM-002, ...\n- Priority must be one of: critical, high, medium, low.\n- Keep prerequisites to 1 to 2 sentences. Keep recommended mitigations concrete.\n\n## Criticality calibration\n- Define what counts as critical/high/medium/low for THIS repo and context.\n- Include 2 to 3 examples per level (tailored to the repo's assets and exposure).\n\n## Focus paths for security review\n- A table: Path | Why it matters | Related Threat IDs\n\n## Notes on use\n\n- Fill in known context, but allow the model to infer and mark assumptions.\n- Include 1–2 repo-path anchors per major claim; do not dump every match.\n","isInternal":false,"tokens":2676,"sizeBytes":12639},{"name":"security-controls-and-assets.md","path":"core/skills/builtin/security-threat-model/references/security-controls-and-assets.md","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/security-threat-model/references/security-controls-and-assets.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Security Controls and Asset Categories\n\nUse this as a lightweight checklist to keep outputs consistent across teams. Prefer concrete, system-specific items over generic text.\n\n## Asset categories (pick only what applies)\n- User data (PII, content, uploads)\n- Authentication artifacts (passwords, tokens, sessions, cookies)\n- Authorization state (roles, policies, ACLs)\n- Secrets and keys (API keys, signing keys, encryption keys)\n- Configuration and feature flags\n- Models and weights (if ML systems)\n- Source code and build artifacts\n- Audit logs and telemetry\n- Availability-critical resources (queues, caches, rate limits, compute budgets)\n- Tenant isolation boundaries and metadata\n\n## Security control categories\n- Identity and access: authN, authZ, session handling, mTLS, key rotation\n- Input protection: schema validation, parsing hardening, upload scanning, sandboxing\n- Network safeguards: TLS, network policies, WAF, rate limiting, DoS controls\n- Data protection: encryption at rest/in transit, tokenization, redaction\n- Isolation: process sandboxing, container boundaries, tenant isolation, seccomp\n- Observability: audit logs, alerting, anomaly detection, tamper resistance\n- Supply chain: dependency pinning, SBOMs, provenance, signing\n- Change control: CI checks, deployment approvals, config guardrails\n\n## Mitigation phrasing patterns\n- \"Enforce schema at <boundary> for <payload> before <component>.\"\n- \"Require authZ check for <action> on <resource> in <service>.\"\n- \"Isolate <parser/component> in a sandbox with <resource limits>.\"\n- \"Rate limit <endpoint> by <key> and apply burst caps.\"\n- \"Encrypt <data> at rest using <key management> and rotate <keys>.\"\n","isInternal":false,"tokens":378,"sizeBytes":1680},{"name":"SKILL.md","path":"core/skills/builtin/security-threat-model/SKILL.md","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/security-threat-model/SKILL.md","title":"security-threat-model","category":"anthropic-skill","format":"markdown","content":"---\nname: \"security-threat-model\"\ndescription: \"Repository-grounded threat modeling that enumerates trust boundaries, assets, attacker capabilities, abuse paths, and mitigations, and writes a concise Markdown threat model. Trigger only when the user explicitly asks to threat model a codebase or path, enumerate threats/abuse paths, or perform AppSec threat modeling. Do not trigger for general architecture summaries, code review, or non-security design work.\"\n---\n\n# Threat Model Source Code Repo\n\nDeliver an actionable AppSec-grade threat model that is specific to the repository or a project path, not a generic checklist. Anchor every architectural claim to evidence in the repo and keep assumptions explicit. Prioritizing realistic attacker goals and concrete impacts over generic checklists.\n\n## Quick start\n\n1) Collect (or infer) inputs:\n- Repo root path and any in-scope paths.\n- Intended usage, deployment model, internet exposure, and auth expectations (if known).\n- Any existing repository summary or architecture spec.\n- Use prompts in `references/prompt-template.md` to generate a repository summary.\n- Follow the required output contract in `references/prompt-template.md`. Use it verbatim when possible.\n\n## Workflow\n\n### 1) Scope and extract the system model\n- Identify primary components, data stores, and external integrations from the repo summary.\n- Identify how the system runs (server, CLI, library, worker) and its entrypoints.\n- Separate runtime behavior from CI/build/dev tooling and from tests/examples.\n- Map the in-scope locations to those components and exclude out-of-scope items explicitly.\n- Do not claim components, flows, or controls without evidence.\n\n### 2) Derive boundaries, assets, and entry points\n- Enumerate trust boundaries as concrete edges between components, noting protocol, auth, encryption, validation, and rate limiting.\n- List assets that drive risk (data, credentials, models, config, compute resources, audit logs).\n- Identify entry points (endpoints, upload surfaces, parsers/decoders, job triggers, admin tooling, logging/error sinks).\n\n### 3) Calibrate assets and attacker capabilities\n- List the assets that drive risk (credentials, PII, integrity-critical state, availability-critical components, build artifacts).\n- Describe realistic attacker capabilities based on exposure and intended usage.\n- Explicitly note non-capabilities to avoid inflated severity.\n\n\n### 4) Enumerate threats as abuse paths\n- Prefer attacker goals that map to assets and boundaries (exfiltration, privilege escalation, integrity compromise, denial of service).\n- Classify each threat and tie it to impacted assets.\n- Keep the number of threats small but high quality.\n\n### 5) Prioritize with explicit likelihood and impact reasoning\n- Use qualitative likelihood and impact (low/medium/high) with short justifications.\n- Set overall priority (critical/high/medium/low) using likelihood x impact, adjusted for existing controls.\n- State which assumptions most influence the ranking.\n\n### 6) Validate service context and assumptions with the user\n- Summarize key assumptions that materially affect threat ranking or scope, then ask the user to confirm or correct them.\n- Ask 1–3 targeted questions to resolve missing context (service owner and environment, scale/users, deployment model, authn/authz, internet exposure, data sensitivity, multi-tenancy).\n- Pause and wait for user feedback before producing the final report.\n- If the user declines or can’t answer, state which assumptions remain and how they influence priority.\n\n### 7) Recommend mitigations and focus paths\n- Distinguish existing mitigations (with evidence) from recommended mitigations.\n- Tie mitigations to concrete locations (component, boundary, or entry point) and control types (authZ checks, input validation, schema enforcement, sandboxing, rate limits, secrets isolation, audit logging).\n- Prefer specific implementation hints over generic advice (e.g., \"enforce schema at gateway for upload payloads\" vs \"validate inputs\").\n- Base recommendations on validated user context; if assumptions remain unresolved, mark recommendations as conditional.\n\n### 8) Run a quality check before finalizing\n- Confirm all discovered entrypoints are covered.\n- Confirm each trust boundary is represented in threats.\n- Confirm runtime vs CI/dev separation.\n- Confirm user clarifications (or explicit non-responses) are reflected.\n- Confirm assumptions and open questions are explicit.\n- Confirm that the format of the report matches closely the required output format defined in prompt template: `references/prompt-template.md`\n- Write the final Markdown to a file named `<repo-or-dir-name>-threat-model.md` (use the basename of the repo root, or the in-scope directory if you were asked to model a subpath).\n\n\n## Risk prioritization guidance (illustrative, not exhaustive)\n- High: pre-auth RCE, auth bypass, cross-tenant access, sensitive data exfiltration, key or token theft, model or config integrity compromise, sandbox escape.\n- Medium: targeted DoS of critical components, partial data exposure, rate-limit bypass with measurable impact, log/metrics poisoning that affects detection.\n- Low: low-sensitivity info leaks, noisy DoS with easy mitigation, issues requiring unlikely preconditions.\n\n## References\n\n- Output contract and full prompt template: `references/prompt-template.md`\n- Optional controls/asset list: `references/security-controls-and-assets.md`\n\nOnly load the reference files you need. Keep the final result concise, grounded, and reviewable.\n","frontmatter":{"name":"security-threat-model","description":"Repository-grounded threat modeling that enumerates trust boundaries, assets, attacker capabilities, abuse paths, and mitigations, and writes a concise Markdown threat model. Trigger only when the user explicitly asks to threat model a codebase or path, enumerate threats/abuse paths, or perform AppSec threat modeling. Do not trigger for general architecture summaries, code review, or non-security design work."},"isInternal":false,"tokens":1112,"sizeBytes":5561},{"name":"openai.yaml","path":"core/skills/builtin/skill-creator/agents/openai.yaml","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/skill-creator/agents/openai.yaml","title":"Agents Skill","category":"anthropic-skill","format":"yaml","content":"interface:\n  display_name: \"Skill Creator\"\n  short_description: \"Create or update a skill\"\n  default_prompt: \"Read my repository and create a skill to bootstrap new components for my project.\"\n","isInternal":false,"tokens":41,"sizeBytes":193},{"name":"openai_yaml.md","path":"core/skills/builtin/skill-creator/references/openai_yaml.md","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/skill-creator/references/openai_yaml.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# openai.yaml fields (full example + descriptions)\n\n`agents/openai.yaml` is an extended, product-specific config intended for the machine/harness to read, not the agent. Other product-specific config can also live in the `agents/` folder.\n\n## Full example\n\n```yaml\ninterface:\n  display_name: \"Optional user-facing name\"\n  short_description: \"Optional user-facing description\"\n  icon_small: \"./assets/small-400px.png\"\n  icon_large: \"./assets/large-logo.svg\"\n  brand_color: \"#3B82F6\"\n  default_prompt: \"Optional surrounding prompt to use the skill with\"\n\ndependencies:\n  tools:\n    - type: \"mcp\"\n      value: \"github\"\n      description: \"GitHub MCP server\"\n      transport: \"streamable_http\"\n      url: \"https://api.githubcopilot.com/mcp/\"\n```\n\n## Field descriptions and constraints\n\nTop-level constraints:\n\n- Quote all string values.\n- Keep keys unquoted.\n- For `interface.default_prompt`: generate a helpful, short (typically 1 sentence) example starting prompt based on the skill. It must explicitly mention the skill as `$skill-name` (e.g., \"Use $skill-name-here to draft a concise weekly status update.\").\n\n- `interface.display_name`: Human-facing title shown in UI skill lists and chips.\n- `interface.short_description`: Human-facing short UI blurb (25–64 chars) for quick scanning.\n- `interface.icon_small`: Path to a small icon asset (relative to skill dir). Default to `./assets/` and place icons in the skill's `assets/` folder.\n- `interface.icon_large`: Path to a larger logo asset (relative to skill dir). Default to `./assets/` and place icons in the skill's `assets/` folder.\n- `interface.brand_color`: Hex color used for UI accents (e.g., badges).\n- `interface.default_prompt`: Default prompt snippet inserted when invoking the skill.\n- `dependencies.tools[].type`: Dependency category. Only `mcp` is supported for now.\n- `dependencies.tools[].value`: Identifier of the tool or dependency.\n- `dependencies.tools[].description`: Human-readable explanation of the dependency.\n- `dependencies.tools[].transport`: Connection type when `type` is `mcp`.\n- `dependencies.tools[].url`: MCP server URL when `type` is `mcp`.\n","isInternal":false,"tokens":492,"sizeBytes":2130},{"name":"SKILL.md","path":"core/skills/builtin/skill-creator/SKILL.md","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/skill-creator/SKILL.md","title":"skill-creator","category":"anthropic-skill","format":"markdown","content":"---\nname: skill-creator\ndescription: Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Codex's capabilities with specialized knowledge, workflows, or tool integrations.\nmetadata:\n  short-description: Create or update a skill\n---\n\n# Skill Creator\n\nThis skill provides guidance for creating effective skills.\n\n## About Skills\n\nSkills are modular, self-contained folders that extend Codex's capabilities by providing\nspecialized knowledge, workflows, and tools. Think of them as \"onboarding guides\" for specific\ndomains or tasks—they transform Codex from a general-purpose agent into a specialized agent\nequipped with procedural knowledge that no model can fully possess.\n\n### What Skills Provide\n\n1. Specialized workflows - Multi-step procedures for specific domains\n2. Tool integrations - Instructions for working with specific file formats or APIs\n3. Domain expertise - Company-specific knowledge, schemas, business logic\n4. Bundled resources - Scripts, references, and assets for complex and repetitive tasks\n\n## Core Principles\n\n### Concise is Key\n\nThe context window is a public good. Skills share the context window with everything else Codex needs: system prompt, conversation history, other Skills' metadata, and the actual user request.\n\n**Default assumption: Codex is already very smart.** Only add context Codex doesn't already have. Challenge each piece of information: \"Does Codex really need this explanation?\" and \"Does this paragraph justify its token cost?\"\n\nPrefer concise examples over verbose explanations.\n\n### Set Appropriate Degrees of Freedom\n\nMatch the level of specificity to the task's fragility and variability:\n\n**High freedom (text-based instructions)**: Use when multiple approaches are valid, decisions depend on context, or heuristics guide the approach.\n\n**Medium freedom (pseudocode or scripts with parameters)**: Use when a preferred pattern exists, some variation is acceptable, or configuration affects behavior.\n\n**Low freedom (specific scripts, few parameters)**: Use when operations are fragile and error-prone, consistency is critical, or a specific sequence must be followed.\n\nThink of Codex as exploring a path: a narrow bridge with cliffs needs specific guardrails (low freedom), while an open field allows many routes (high freedom).\n\n### Anatomy of a Skill\n\nEvery skill consists of a required SKILL.md file and optional bundled resources:\n\n```\nskill-name/\n├── SKILL.md (required)\n│   ├── YAML frontmatter metadata (required)\n│   │   ├── name: (required)\n│   │   └── description: (required)\n│   └── Markdown instructions (required)\n├── agents/ (recommended)\n│   └── openai.yaml - UI metadata for skill lists and chips\n└── Bundled Resources (optional)\n    ├── scripts/          - Executable code (Python/Bash/etc.)\n    ├── references/       - Documentation intended to be loaded into context as needed\n    └── assets/           - Files used in output (templates, icons, fonts, etc.)\n```\n\n#### SKILL.md (required)\n\nEvery SKILL.md consists of:\n\n- **Frontmatter** (YAML): Contains `name` and `description` fields. These are the only fields that Codex reads to determine when the skill gets used, thus it is very important to be clear and comprehensive in describing what the skill is, and when it should be used.\n- **Body** (Markdown): Instructions and guidance for using the skill. Only loaded AFTER the skill triggers (if at all).\n\n#### Agents metadata (recommended)\n\n- UI-facing metadata for skill lists and chips\n- Read references/openai_yaml.md before generating values and follow its descriptions and constraints\n- Create: human-facing `display_name`, `short_description`, and `default_prompt` by reading the skill\n- Generate deterministically by passing the values as `--interface key=value` to `scripts/generate_openai_yaml.py` or `scripts/init_skill.py`\n- On updates: validate `agents/openai.yaml` still matches SKILL.md; regenerate if stale\n- Only include other optional interface fields (icons, brand color) if explicitly provided\n- See references/openai_yaml.md for field definitions and examples\n\n#### Bundled Resources (optional)\n\n##### Scripts (`scripts/`)\n\nExecutable code (Python/Bash/etc.) for tasks that require deterministic reliability or are repeatedly rewritten.\n\n- **When to include**: When the same code is being rewritten repeatedly or deterministic reliability is needed\n- **Example**: `scripts/rotate_pdf.py` for PDF rotation tasks\n- **Benefits**: Token efficient, deterministic, may be executed without loading into context\n- **Note**: Scripts may still need to be read by Codex for patching or environment-specific adjustments\n\n##### References (`references/`)\n\nDocumentation and reference material intended to be loaded as needed into context to inform Codex's process and thinking.\n\n- **When to include**: For documentation that Codex should reference while working\n- **Examples**: `references/finance.md` for financial schemas, `references/mnda.md` for company NDA template, `references/policies.md` for company policies, `references/api_docs.md` for API specifications\n- **Use cases**: Database schemas, API documentation, domain knowledge, company policies, detailed workflow guides\n- **Benefits**: Keeps SKILL.md lean, loaded only when Codex determines it's needed\n- **Best practice**: If files are large (>10k words), include grep search patterns in SKILL.md\n- **Avoid duplication**: Information should live in either SKILL.md or references files, not both. Prefer references files for detailed information unless it's truly core to the skill—this keeps SKILL.md lean while making information discoverable without hogging the context window. Keep only essential procedural instructions and workflow guidance in SKILL.md; move detailed reference material, schemas, and examples to references files.\n\n##### Assets (`assets/`)\n\nFiles not intended to be loaded into context, but rather used within the output Codex produces.\n\n- **When to include**: When the skill needs files that will be used in the final output\n- **Examples**: `assets/logo.png` for brand assets, `assets/slides.pptx` for PowerPoint templates, `assets/frontend-template/` for HTML/React boilerplate, `assets/font.ttf` for typography\n- **Use cases**: Templates, images, icons, boilerplate code, fonts, sample documents that get copied or modified\n- **Benefits**: Separates output resources from documentation, enables Codex to use files without loading them into context\n\n#### What to Not Include in a Skill\n\nA skill should only contain essential files that directly support its functionality. Do NOT create extraneous documentation or auxiliary files, including:\n\n- README.md\n- INSTALLATION_GUIDE.md\n- QUICK_REFERENCE.md\n- CHANGELOG.md\n- etc.\n\nThe skill should only contain the information needed for an AI agent to do the job at hand. It should not contain auxiliary context about the process that went into creating it, setup and testing procedures, user-facing documentation, etc. Creating additional documentation files just adds clutter and confusion.\n\n### Progressive Disclosure Design Principle\n\nSkills use a three-level loading system to manage context efficiently:\n\n1. **Metadata (name + description)** - Always in context (~100 words)\n2. **SKILL.md body** - When skill triggers (<5k words)\n3. **Bundled resources** - As needed by Codex (Unlimited because scripts can be executed without reading into context window)\n\n#### Progressive Disclosure Patterns\n\nKeep SKILL.md body to the essentials and under 500 lines to minimize context bloat. Split content into separate files when approaching this limit. When splitting out content into other files, it is very important to reference them from SKILL.md and describe clearly when to read them, to ensure the reader of the skill knows they exist and when to use them.\n\n**Key principle:** When a skill supports multiple variations, frameworks, or options, keep only the core workflow and selection guidance in SKILL.md. Move variant-specific details (patterns, examples, configuration) into separate reference files.\n\n**Pattern 1: High-level guide with references**\n\n```markdown\n# PDF Processing\n\n## Quick start\n\nExtract text with pdfplumber:\n[code example]\n\n## Advanced features\n\n- **Form filling**: See [FORMS.md](FORMS.md) for complete guide\n- **API reference**: See [REFERENCE.md](REFERENCE.md) for all methods\n- **Examples**: See [EXAMPLES.md](EXAMPLES.md) for common patterns\n```\n\nCodex loads FORMS.md, REFERENCE.md, or EXAMPLES.md only when needed.\n\n**Pattern 2: Domain-specific organization**\n\nFor Skills with multiple domains, organize content by domain to avoid loading irrelevant context:\n\n```\nbigquery-skill/\n├── SKILL.md (overview and navigation)\n└── reference/\n    ├── finance.md (revenue, billing metrics)\n    ├── sales.md (opportunities, pipeline)\n    ├── product.md (API usage, features)\n    └── marketing.md (campaigns, attribution)\n```\n\nWhen a user asks about sales metrics, Codex only reads sales.md.\n\nSimilarly, for skills supporting multiple frameworks or variants, organize by variant:\n\n```\ncloud-deploy/\n├── SKILL.md (workflow + provider selection)\n└── references/\n    ├── aws.md (AWS deployment patterns)\n    ├── gcp.md (GCP deployment patterns)\n    └── azure.md (Azure deployment patterns)\n```\n\nWhen the user chooses AWS, Codex only reads aws.md.\n\n**Pattern 3: Conditional details**\n\nShow basic content, link to advanced content:\n\n```markdown\n# DOCX Processing\n\n## Creating documents\n\nUse docx-js for new documents. See [DOCX-JS.md](DOCX-JS.md).\n\n## Editing documents\n\nFor simple edits, modify the XML directly.\n\n**For tracked changes**: See [REDLINING.md](REDLINING.md)\n**For OOXML details**: See [OOXML.md](OOXML.md)\n```\n\nCodex reads REDLINING.md or OOXML.md only when the user needs those features.\n\n**Important guidelines:**\n\n- **Avoid deeply nested references** - Keep references one level deep from SKILL.md. All reference files should link directly from SKILL.md.\n- **Structure longer reference files** - For files longer than 100 lines, include a table of contents at the top so Codex can see the full scope when previewing.\n\n## Skill Creation Process\n\nSkill creation involves these steps:\n\n1. Understand the skill with concrete examples\n2. Plan reusable skill contents (scripts, references, assets)\n3. Initialize the skill (run init_skill.py)\n4. Edit the skill (implement resources and write SKILL.md)\n5. Validate the skill (run quick_validate.py)\n6. Iterate based on real usage\n\nFollow these steps in order, skipping only if there is a clear reason why they are not applicable.\n\n### Skill Naming\n\n- Use lowercase letters, digits, and hyphens only; normalize user-provided titles to hyphen-case (e.g., \"Plan Mode\" -> `plan-mode`).\n- When generating names, generate a name under 64 characters (letters, digits, hyphens).\n- Prefer short, verb-led phrases that describe the action.\n- Namespace by tool when it improves clarity or triggering (e.g., `gh-address-comments`, `linear-address-issue`).\n- Name the skill folder exactly after the skill name.\n\n### Step 1: Understanding the Skill with Concrete Examples\n\nSkip this step only when the skill's usage patterns are already clearly understood. It remains valuable even when working with an existing skill.\n\nTo create an effective skill, clearly understand concrete examples of how the skill will be used. This understanding can come from either direct user examples or generated examples that are validated with user feedback.\n\nFor example, when building an image-editor skill, relevant questions include:\n\n- \"What functionality should the image-editor skill support? Editing, rotating, anything else?\"\n- \"Can you give some examples of how this skill would be used?\"\n- \"I can imagine users asking for things like 'Remove the red-eye from this image' or 'Rotate this image'. Are there other ways you imagine this skill being used?\"\n- \"What would a user say that should trigger this skill?\"\n\nTo avoid overwhelming users, avoid asking too many questions in a single message. Start with the most important questions and follow up as needed for better effectiveness.\n\nConclude this step when there is a clear sense of the functionality the skill should support.\n\n### Step 2: Planning the Reusable Skill Contents\n\nTo turn concrete examples into an effective skill, analyze each example by:\n\n1. Considering how to execute on the example from scratch\n2. Identifying what scripts, references, and assets would be helpful when executing these workflows repeatedly\n\nExample: When building a `pdf-editor` skill to handle queries like \"Help me rotate this PDF,\" the analysis shows:\n\n1. Rotating a PDF requires re-writing the same code each time\n2. A `scripts/rotate_pdf.py` script would be helpful to store in the skill\n\nExample: When designing a `frontend-webapp-builder` skill for queries like \"Build me a todo app\" or \"Build me a dashboard to track my steps,\" the analysis shows:\n\n1. Writing a frontend webapp requires the same boilerplate HTML/React each time\n2. An `assets/hello-world/` template containing the boilerplate HTML/React project files would be helpful to store in the skill\n\nExample: When building a `big-query` skill to handle queries like \"How many users have logged in today?\" the analysis shows:\n\n1. Querying BigQuery requires re-discovering the table schemas and relationships each time\n2. A `references/schema.md` file documenting the table schemas would be helpful to store in the skill\n\nTo establish the skill's contents, analyze each concrete example to create a list of the reusable resources to include: scripts, references, and assets.\n\n### Step 3: Initializing the Skill\n\nAt this point, it is time to actually create the skill.\n\nSkip this step only if the skill being developed already exists. In this case, continue to the next step.\n\nWhen creating a new skill from scratch, always run the `init_skill.py` script. The script conveniently generates a new template skill directory that automatically includes everything a skill requires, making the skill creation process much more efficient and reliable.\n\nUsage:\n\n```bash\nscripts/init_skill.py <skill-name> --path <output-directory> [--resources scripts,references,assets] [--examples]\n```\n\nExamples:\n\n```bash\nscripts/init_skill.py my-skill --path skills/public\nscripts/init_skill.py my-skill --path skills/public --resources scripts,references\nscripts/init_skill.py my-skill --path skills/public --resources scripts --examples\n```\n\nThe script:\n\n- Creates the skill directory at the specified path\n- Generates a SKILL.md template with proper frontmatter and TODO placeholders\n- Creates `agents/openai.yaml` using agent-generated `display_name`, `short_description`, and `default_prompt` passed via `--interface key=value`\n- Optionally creates resource directories based on `--resources`\n- Optionally adds example files when `--examples` is set\n\nAfter initialization, customize the SKILL.md and add resources as needed. If you used `--examples`, replace or delete placeholder files.\n\nGenerate `display_name`, `short_description`, and `default_prompt` by reading the skill, then pass them as `--interface key=value` to `init_skill.py` or regenerate with:\n\n```bash\nscripts/generate_openai_yaml.py <path/to/skill-folder> --interface key=value\n```\n\nOnly include other optional interface fields when the user explicitly provides them. For full field descriptions and examples, see references/openai_yaml.md.\n\n### Step 4: Edit the Skill\n\nWhen editing the (newly-generated or existing) skill, remember that the skill is being created for another instance of Codex to use. Include information that would be beneficial and non-obvious to Codex. Consider what procedural knowledge, domain-specific details, or reusable assets would help another Codex instance execute these tasks more effectively.\n\n#### Start with Reusable Skill Contents\n\nTo begin implementation, start with the reusable resources identified above: `scripts/`, `references/`, and `assets/` files. Note that this step may require user input. For example, when implementing a `brand-guidelines` skill, the user may need to provide brand assets or templates to store in `assets/`, or documentation to store in `references/`.\n\nAdded scripts must be tested by actually running them to ensure there are no bugs and that the output matches what is expected. If there are many similar scripts, only a representative sample needs to be tested to ensure confidence that they all work while balancing time to completion.\n\nIf you used `--examples`, delete any placeholder files that are not needed for the skill. Only create resource directories that are actually required.\n\n#### Update SKILL.md\n\n**Writing Guidelines:** Always use imperative/infinitive form.\n\n##### Frontmatter\n\nWrite the YAML frontmatter with `name` and `description`:\n\n- `name`: The skill name\n- `description`: This is the primary triggering mechanism for your skill, and helps Codex understand when to use the skill.\n  - Include both what the Skill does and specific triggers/contexts for when to use it.\n  - Include all \"when to use\" information here - Not in the body. The body is only loaded after triggering, so \"When to Use This Skill\" sections in the body are not helpful to Codex.\n  - Example description for a `docx` skill: \"Comprehensive document creation, editing, and analysis with support for tracked changes, comments, formatting preservation, and text extraction. Use when Codex needs to work with professional documents (.docx files) for: (1) Creating new documents, (2) Modifying or editing content, (3) Working with tracked changes, (4) Adding comments, or any other document tasks\"\n\nDo not include any other fields in YAML frontmatter.\n\n##### Body\n\nWrite instructions for using the skill and its bundled resources.\n\n### Step 5: Validate the Skill\n\nOnce development of the skill is complete, validate the skill folder to catch basic issues early:\n\n```bash\nscripts/quick_validate.py <path/to/skill-folder>\n```\n\nThe validation script checks YAML frontmatter format, required fields, and naming rules. If validation fails, fix the reported issues and run the command again.\n\n### Step 6: Iterate\n\nAfter testing the skill, users may request improvements. Often this happens right after using the skill, with fresh context of how the skill performed.\n\n**Iteration workflow:**\n\n1. Use the skill on real tasks\n2. Notice struggles or inefficiencies\n3. Identify how SKILL.md or bundled resources should be updated\n4. Implement changes and test again\n","frontmatter":{"name":"skill-creator","description":"Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Codex's capabilities with specialized knowledge, workflows, or tool integrations.","metadata":{"short-description":"Create or update a skill"}},"isInternal":false,"tokens":3892,"sizeBytes":18664},{"name":"UPSTREAM_SOURCES.json","path":"core/skills/builtin/UPSTREAM_SOURCES.json","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/UPSTREAM_SOURCES.json","title":"Builtin Skill","category":"anthropic-skill","format":"json","content":"{\n  \"schemaVersion\": 1,\n  \"skills\": {\n    \"frontend-design\": {\n      \"repository\": \"https://github.com/anthropics/skills\",\n      \"revision\": \"f17010c9bb483898c1d9c9f42dde2b3a98889434\",\n      \"path\": \"skills/frontend-design\"\n    },\n    \"mcp-builder\": {\n      \"repository\": \"https://github.com/anthropics/skills\",\n      \"revision\": \"f17010c9bb483898c1d9c9f42dde2b3a98889434\",\n      \"path\": \"skills/mcp-builder\"\n    },\n    \"review-agent\": {\n      \"repository\": \"https://github.com/openai/codex\",\n      \"revision\": \"4ef836f883c38ba6d39e6920f335ce6452b7de33\",\n      \"path\": \"codex-rs/skills/src/assets/samples/review-agent\"\n    },\n    \"security-best-practices\": {\n      \"repository\": \"https://github.com/openai/skills\",\n      \"revision\": \"49f948faa9258a0c61caceaf225e179651397431\",\n      \"path\": \"skills/.curated/security-best-practices\"\n    },\n    \"security-ownership-map\": {\n      \"repository\": \"https://github.com/openai/skills\",\n      \"revision\": \"49f948faa9258a0c61caceaf225e179651397431\",\n      \"path\": \"skills/.curated/security-ownership-map\"\n    },\n    \"security-threat-model\": {\n      \"repository\": \"https://github.com/openai/skills\",\n      \"revision\": \"49f948faa9258a0c61caceaf225e179651397431\",\n      \"path\": \"skills/.curated/security-threat-model\"\n    },\n    \"skill-creator\": {\n      \"repository\": \"https://github.com/openai/skills\",\n      \"revision\": \"49f948faa9258a0c61caceaf225e179651397431\",\n      \"path\": \"skills/.system/skill-creator\"\n    },\n    \"webapp-testing\": {\n      \"repository\": \"https://github.com/anthropics/skills\",\n      \"revision\": \"f17010c9bb483898c1d9c9f42dde2b3a98889434\",\n      \"path\": \"skills/webapp-testing\"\n    }\n  }\n}\n","frontmatter":{"schemaVersion":1,"skills":{"frontend-design":{"repository":"https://github.com/anthropics/skills","revision":"f17010c9bb483898c1d9c9f42dde2b3a98889434","path":"skills/frontend-design"},"mcp-builder":{"repository":"https://github.com/anthropics/skills","revision":"f17010c9bb483898c1d9c9f42dde2b3a98889434","path":"skills/mcp-builder"},"review-agent":{"repository":"https://github.com/openai/codex","revision":"4ef836f883c38ba6d39e6920f335ce6452b7de33","path":"codex-rs/skills/src/assets/samples/review-agent"},"security-best-practices":{"repository":"https://github.com/openai/skills","revision":"49f948faa9258a0c61caceaf225e179651397431","path":"skills/.curated/security-best-practices"},"security-ownership-map":{"repository":"https://github.com/openai/skills","revision":"49f948faa9258a0c61caceaf225e179651397431","path":"skills/.curated/security-ownership-map"},"security-threat-model":{"repository":"https://github.com/openai/skills","revision":"49f948faa9258a0c61caceaf225e179651397431","path":"skills/.curated/security-threat-model"},"skill-creator":{"repository":"https://github.com/openai/skills","revision":"49f948faa9258a0c61caceaf225e179651397431","path":"skills/.system/skill-creator"},"webapp-testing":{"repository":"https://github.com/anthropics/skills","revision":"f17010c9bb483898c1d9c9f42dde2b3a98889434","path":"skills/webapp-testing"}}},"isInternal":false,"tokens":533,"sizeBytes":1651},{"name":"SKILL.md","path":"core/skills/builtin/webapp-testing/SKILL.md","rawUrl":"https://raw.githubusercontent.com/HKUDS/DeepCode/HEAD/core/skills/builtin/webapp-testing/SKILL.md","title":"webapp-testing","category":"anthropic-skill","format":"markdown","content":"---\nname: webapp-testing\ndescription: Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.\nlicense: Complete terms in LICENSE.txt\n---\n\n# Web Application Testing\n\nTo test local web applications, write native Python Playwright scripts.\n\n**Helper Scripts Available**:\n- `scripts/with_server.py` - Manages server lifecycle (supports multiple servers)\n\n**Always run scripts with `--help` first** to see usage. DO NOT read the source until you try running the script first and find that a customized solution is abslutely necessary. These scripts can be very large and thus pollute your context window. They exist to be called directly as black-box scripts rather than ingested into your context window.\n\n## Decision Tree: Choosing Your Approach\n\n```\nUser task → Is it static HTML?\n    ├─ Yes → Read HTML file directly to identify selectors\n    │         ├─ Success → Write Playwright script using selectors\n    │         └─ Fails/Incomplete → Treat as dynamic (below)\n    │\n    └─ No (dynamic webapp) → Is the server already running?\n        ├─ No → Run: python scripts/with_server.py --help\n        │        Then use the helper + write simplified Playwright script\n        │\n        └─ Yes → Reconnaissance-then-action:\n            1. Navigate and wait for networkidle\n            2. Take screenshot or inspect DOM\n            3. Identify selectors from rendered state\n            4. Execute actions with discovered selectors\n```\n\n## Example: Using with_server.py\n\nTo start a server, run `--help` first, then use the helper:\n\n**Single server:**\n```bash\npython scripts/with_server.py --server \"npm run dev\" --port 5173 -- python your_automation.py\n```\n\n**Multiple servers (e.g., backend + frontend):**\n```bash\npython scripts/with_server.py \\\n  --server \"cd backend && python server.py\" --port 3000 \\\n  --server \"cd frontend && npm run dev\" --port 5173 \\\n  -- python your_automation.py\n```\n\nTo create an automation script, include only Playwright logic (servers are managed automatically):\n```python\nfrom playwright.sync_api import sync_playwright\n\nwith sync_playwright() as p:\n    browser = p.chromium.launch(headless=True) # Always launch chromium in headless mode\n    page = browser.new_page()\n    page.goto('http://localhost:5173') # Server already running and ready\n    page.wait_for_load_state('networkidle') # CRITICAL: Wait for JS to execute\n    # ... your automation logic\n    browser.close()\n```\n\n## Reconnaissance-Then-Action Pattern\n\n1. **Inspect rendered DOM**:\n   ```python\n   page.screenshot(path='/tmp/inspect.png', full_page=True)\n   content = page.content()\n   page.locator('button').all()\n   ```\n\n2. **Identify selectors** from inspection results\n\n3. **Execute actions** using discovered selectors\n\n## Common Pitfall\n\n❌ **Don't** inspect the DOM before waiting for `networkidle` on dynamic apps\n✅ **Do** wait for `page.wait_for_load_state('networkidle')` before inspection\n\n## Best Practices\n\n- **Use bundled scripts as black boxes** - To accomplish a task, consider whether one of the scripts available in `scripts/` can help. These scripts handle common, complex workflows reliably without cluttering the context window. Use `--help` to see usage, then invoke directly.\n- Use `sync_playwright()` for synchronous scripts\n- Always close the browser when done\n- Use descriptive selectors: `text=`, `role=`, CSS selectors, or IDs\n- Add appropriate waits: `page.wait_for_selector()` or `page.wait_for_timeout()`\n\n## Reference Files\n\n- **examples/** - Examples showing common patterns:\n  - `element_discovery.py` - Discovering buttons, links, and inputs on a page\n  - `static_html_automation.py` - Using file:// URLs for local HTML\n  - `console_logging.py` - Capturing console logs during automation\n","frontmatter":{"name":"webapp-testing","description":"Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.","license":"Complete terms in LICENSE.txt"},"isInternal":false,"tokens":881,"sizeBytes":3913}],"systemPromptSnippet":"<yakaai_skills repo=\"HKUDS/DeepCode\">\n<!-- File: core/skills/builtin/frontend-design/SKILL.md (Tokens: ~1668 | Category: anthropic-skill) -->\n---\nname: frontend-design\ndescription: Guidance for distinctive, intentional visual design when building new UI or reshaping an existing one. Helps with aesthetic direction, typography, and making choices that don't read as templated defaults.\nlicense: Complete terms in LICENSE.txt\n---\n\n# Frontend Design\n\nApproach this as the design lead at a small studio known for giving every client a visual identity that could not be mistaken for anyone else's. This client has already rejected proposals that felt templated, and is paying for a distinctive point of view: make deliberate, opinionated choices about palette, typography, and layout that are specific to this brief, and take one real aesthetic risk you can justify.\n\n## Ground it in the subject\n\nIf the brief does not pin down what the product or subject is, pin it yourself before designing: name one concrete subject, its audience, and the page's single job, and state your choice. If there's any information in your memory about the human's preferences, context about what they're building, or designs you've made before – use that as a hint. The subject's own world, its materials, instruments, artifacts, and vernacular, is where distinctive choices come from. Build with the brief's real content and subject matter throughout.\n\n## Design principles\n\nFor web designs, the hero is a thesis. Open with the most characteristic thing in the subject's world, in whatever form makes sense for it: a headline, an image, an animation, a live demo, an interactive moment. Be deliberate with your choice: a big number with a small label, supporting stats, and a gradient accent is the template answer, only use if that's truly the best option.\n\nTypography carries the personality of the page. Pair the display and body faces deliberately, not the same families you would reach for on any other project, and set a clear type scale with intentional weights, widths, and spacing. Make the type treatment itself a memorable part of the design, not a neutral delivery vehicle for the content.\n\nStructure is information. Structural devices, numbering, eyebrows, dividers, labels, should encode something true about the content, not decorate it. Many generic designs use numbered markers (01 / 02 / 03), but that's only appropriate if the content actually is a sequence - like a real process or a typed timeline where order carries information the reader needs. Question if choices like numbered markers actually make sense before incorporating them.\n\nLeverage motion deliberately. Think about where and if animation can serve the subject: a page-load sequence, a scroll-triggered reveal, hover micro-interactions, ambient atmosphere. An orchestrated moment usually lands harder than scattered effects; choose what the direction calls for. However, sometimes less is more, and extra animation contributes to the feeling that the design is AI-generated.\n\nMatch complexity to the vision. Maximalist directions need elaborate execution; minimal directions need precision in spacing, type, and detail. Elegance is executing the chosen vision well.\n\nConsider written content carefully. Often a design brief may not contain real content, and it's up to you to come up with copy. Copy can make a design feel as templated as the design itself. See the below section on writing for more guidance.\n\n## Process: brainstorm, explore, plan, critique, build, critique again\n\nFor calibration: AI-generated design right now clusters around three looks: (1) a warm cream background (near #F4F1EA) with a high-contrast serif display and a terracotta accent; (2) a near-black background with a single bright acid-green or vermilion accent; (3) a broadsheet-style layout with hairline rules, zero border-radius, and dense newspaper-like columns. All three are legitimate for some briefs, but they are defaults rather than choices, and they appear regardless of subject. Where the brief pins down a visual direction, follow it exactly — the brief's own words always win, including when it asks for one of these looks. Where it leaves an axis free, don't spend that freedom on one of these defaults. Just like a human designer who's hired, there's often a careful balance between doing what you're good at and taking each project as a chance to experiment and learn.\n\nWork in two passes. First, brainstorm a short design plan based on the human's design brief: create a compact token system with color, type, layout, and signature. Color: describe the palette as 4–6 named hex values. Type: the typefaces for 2+ roles (a characterful display face that's used with restraint, a complementary body face, and a utility face for captions or data if needed). Layout: a layout concept, using one-sentence prose descriptions and ASCII wireframes to ideate and compare. Signature: the single unique element this page will be remembered by that embodies the brief in an appropriate way.\n\nThen review that plan against the brief before building: if any part of it reads like the generic default you would produce for any similar page (work through a similar prompt to see if you arrive somewhere similar) rather than a choice made for this specific brief — revise that part, say what you changed and why. Only after you've confirmed the relative uniqueness of your design plan should you start to write the code, following the revised plan exactly and deriving every color and type decision from it.\n\nWhen writing the code, be careful of structuring your CSS selector specificities. It's easy to generate CSS classes that cancel each other out (especially with a type-based selector like .section and a element-based selector like .cta). This can happen often with paddings/margins between sections.\n\nTry to do a lot of this planning and iteration in your thinking, and only show ideas to the user when you have higher confidence it'll delight them.\n\n## Restraint and self-critique\n\nSpend your boldness in one place. Let the signature element be the one memorable thing, keep everything around it quiet and disciplined, and cut any decoration that does not serve the brief. Not taking a risk can be a risk itself! Build to a quality floor without announcing it: responsive down to mobile, visible keyboard focus, reduced motion respected. Critique your own work as you build, taking screenshots if your environment supports it – a picture is worth 1000 tokens. Consider Chanel's advice: before leaving the house, take a look in the mirror and remove one accessory. Human creators have memory and always try to do something new, so if you have a space to quickly jot down notes about what you've tried, it can help you in future passes.\n\n## More on writing in design\n\nWords appear in a design for one reason: to make it easier to understand, and therefore easier to use. They are design material, not decoration. Bring the same intentionality to copy that you would bring to spacing and color. Before writing anything, ask what the design needs to say, and how it can best be said to help the person navigate the experience.\n\nWrite from the end user's side of the screen. Name things by what people control and recognize, never by how the system is built. A person manages notifications, not webhook config. Describe what something does in plain terms rather than selling it. Being specific is always better than being clever.\n\nUse active voice as default. A control should say exactly what happens when it's used: \"Save changes,\" not \"Submit.\" An action keeps the same name through the whole flow, so the button that says \"Publish\" produces a toast that says \"Published.\" The vocabulary of an interface is the signposting for someone navigating the product. Cohesion and consistency are how people learn their way around.\n\nTreat failure and emptiness as moments for direction, not mood. Explain what went wrong and how to fix it, in the interface's voice rather than a person's. Errors don't apologize, and they are never vague about what happened. An empty screen is an invitation to act.\n\nKeep the register conversational and tuned: plain verbs, sentence case, no filler, with tone matched to the brand and the audience. Let each element do exactly one job. A label labels, an example demonstrates, and nothing quietly does double duty.\n\n<!-- File: core/skills/builtin/mcp-builder/reference/evaluation.md (Tokens: ~4939 | Category: anthropic-skill) -->\n# MCP Server Evaluation Guide\n\n## Overview\n\nThis document provides guidance on creating comprehensive evaluations for MCP servers. Evaluations test whether LLMs can effectively use your MCP server to answer realistic, complex questions using only the tools provided.\n\n---\n\n## Quick Reference\n\n### Evaluation Requirements\n- Create 10 human-readable questions\n- Questions must be READ-ONLY, INDEPENDENT, NON-DESTRUCTIVE\n- Each question requires multiple tool calls (potentially dozens)\n- Answers must be single, verifiable values\n- Answers must be STABLE (won't change over time)\n\n### Output Format\n```xml\n<evaluation>\n   <qa_pair>\n      <question>Your question here</question>\n      <answer>Single verifiable answer</answer>\n   </qa_pair>\n</evaluation>\n```\n\n---\n\n## Purpose of Evaluations\n\nThe measure of quality of an MCP server is NOT how well or comprehensively the server implements tools, but how well these implementations (input/output schemas, docstrings/descriptions, functionality) enable LLMs with no other context and access ONLY to the MCP servers to answer realistic and difficult questions.\n\n## Evaluation Overview\n\nCreate 10 human-readable questions requiring ONLY READ-ONLY, INDEPENDENT, NON-DESTRUCTIVE, and IDEMPOTENT operations to answer. Each question should be:\n- Realistic\n- Clear and concise\n- Unambiguous\n- Complex, requiring potentially dozens of tool calls or steps\n- Answerable with a single, verifiable value that you identify in advance\n\n## Question Guidelines\n\n### Core Requirements\n\n1. **Questions MUST be independent**\n   - Each question should NOT depend on the answer to any other question\n   - Should not assume prior write operations from processing another question\n\n2. **Questions MUST require ONLY NON-DESTRUCTIVE AND IDEMPOTENT tool use**\n   - Should not instruct or require modifying state to arrive at the correct answer\n\n3. **Questions must be REALISTIC, CLEAR, CONCISE, and COMPLEX**\n   - Must require another LLM to use multiple (potentially dozens of) tools or steps to answer\n\n### Complexity and Depth\n\n4. **Questions must require deep exploration**\n   - Consider multi-hop questions requiring multiple sub-questions and sequential tool calls\n   - Each step should benefit from information found in previous questions\n\n5. **Questions may require extensive paging**\n   - May need paging through multiple pages of results\n   - May require querying old data (1-2 years out-of-date) to find niche information\n   - The questions must be DIFFICULT\n\n6. **Questions must require deep understanding**\n   - Rather than surface-level knowledge\n   - May pose complex ideas as True/False questions requiring evidence\n   - May use multiple-choice format where LLM must search different hypotheses\n\n7. **Questions must not be solvable with straightforward keyword search**\n   - Do not include specific keywords from the target content\n   - Use synonyms, related concepts, or paraphrases\n   - Require multiple searches, analyzing multiple related items, extracting context, then deriving the answer\n\n### Tool Testing\n\n8. **Questions should stress-test tool return values**\n   - May elicit tools returning large JSON objects or lists, overwhelming the LLM\n   - Should require understanding multiple modalities of data:\n     - IDs and names\n     - Timestamps and datetimes (months, days, years, seconds)\n     - File IDs, names, extensions, and mimetypes\n     - URLs, GIDs, etc.\n   - Should probe the tool's ability to return all useful forms of data\n\n9. **Questions should MOSTLY reflect real human use cases**\n   - The kinds of information retrieval tasks that HUMANS assisted by an LLM would care about\n\n10. **Questions may require dozens of tool calls**\n    - This challenges LLMs with limited context\n    - Encourages MCP server tools to reduce information returned\n\n11. **Include ambiguous questions**\n    - May be ambiguous OR require difficult decisions on which tools to call\n    - Force the LLM to potentially make mistakes or misinterpret\n    - Ensure that despite AMBIGUITY, there is STILL A SINGLE VERIFIABLE ANSWER\n\n### Stability\n\n12. **Questions must be designed so the answer DOES NOT CHANGE**\n    - Do not ask questions that rely on \"current state\" which is dynamic\n    - For example, do not count:\n      - Number of reactions to a post\n      - Number of replies to a thread\n      - Number of members in a channel\n\n13. **DO NOT let the MCP server RESTRICT the kinds of questions you create**\n    - Create challenging and complex questions\n    - Some may not be solvable with the available MCP server tools\n    - Questions may require specific output formats (datetime vs. epoch time, JSON vs. MARKDOWN)\n    - Questions may require dozens of tool calls to complete\n\n## Answer Guidelines\n\n### Verification\n\n1. **Answers must be VERIFIABLE via direct string comparison**\n   - If the answer can be re-written in many formats, clearly specify the output format in the QUESTION\n   - Examples: \"Use YYYY/MM/DD.\", \"Respond True or False.\", \"Answer A, B, C, or D and nothing else.\"\n   - Answer should be a single VERIFIABLE value such as:\n     - User ID, user name, display name, first name, last name\n     - Channel ID, channel name\n     - Message ID, string\n     - URL, title\n     - Numerical quantity\n     - Timestamp, datetime\n     - Boolean (for True/False questions)\n     - Email address, phone number\n     - File ID, file name, file extension\n     - Multiple choice answer\n   - Answers must not require special formatting or complex, structured output\n   - Answer will be verified using DIRECT STRING COMPARISON\n\n### Readability\n\n2. **Answers should generally prefer HUMAN-READABLE formats**\n   - Examples: names, first name, last name, datetime, file name, message string, URL, yes/no, true/false, a/b/c/d\n   - Rather than opaque IDs (though IDs are acceptable)\n   - The VAST MAJORITY of answers should be human-readable\n\n### Stability\n\n3. **Answers must be STABLE/STATIONARY**\n   - Look at old content (e.g., conversations that have ended, projects that have launched, questions answered)\n   - Create QUESTIONS based on \"closed\" concepts that will always return the same answer\n   - Questions may ask to consider a fixed time window to insulate from non-stationary answers\n   - Rely on context UNLIKELY to change\n   - Example: if finding a paper name, be SPECIFIC enough so answer is not confused with papers published later\n\n4. **Answers must be CLEAR and UNAMBIGUOUS**\n   - Questions must be designed so there is a single, clear answer\n   - Answer can be derived from using the MCP server tools\n\n### Diversity\n\n5. **Answers must be DIVERSE**\n   - Answer should be a single VERIFIABLE value in diverse modalities and formats\n   - User concept: user ID, user name, display name, first name, last name, email address, phone number\n   - Channel concept: channel ID, channel name, channel topic\n   - Message concept: message ID, message string, timestamp, month, day, year\n\n6. **Answers must NOT be complex structures**\n   - Not a list of values\n   - Not a complex object\n   - Not a list of IDs or strings\n   - Not natural language text\n   - UNLESS the answer can be straightforwardly verified using DIRECT STRING COMPARISON\n   - And can be realistically reproduced\n   - It should be unlikely that an LLM would return the same list in any other order or format\n\n## Evaluation Process\n\n### Step 1: Documentation Inspection\n\nRead the documentation of the target API to understand:\n- Available endpoints and functionality\n- If ambiguity exists, fetch additional information from the web\n- Parallelize this step AS MUCH AS POSSIBLE\n- Ensure each subagent is ONLY examining documentation from the file system or on the web\n\n### Step 2: Tool Inspection\n\nList the tools available in the MCP server:\n- Inspect the MCP server directly\n- Understand input/output schemas, docstrings, and descriptions\n- WITHOUT calling the tools themselves at this stage\n\n### Step 3: Developing Understanding\n\nRepeat steps 1 & 2 until you have a good understanding:\n- Iterate multiple times\n- Think about the kinds of tasks you want to create\n- Refine your understanding\n- At NO stage should you READ the code of the MCP server implementation itself\n- Use your intuition and understanding to create reasonable, realistic, but VERY challenging tasks\n\n### Step 4: Read-Only Content Inspection\n\nAfter understanding the API and tools, USE the MCP server tools:\n- Inspect content using READ-ONLY and NON-DESTRUCTIVE operations ONLY\n- Goal: identify specific content (e.g., users, channels, messages, projects, tasks) for creating realistic questions\n- Should NOT call any tools that modify state\n- Will NOT read the code of the MCP server implementation itself\n- Parallelize this step with individual sub-agents pursuing independent explorations\n- Ensure each subagent is only performing READ-ONLY, NON-DESTRUCTIVE, and IDEMPOTENT operations\n- BE CAREFUL: SOME TOOLS may return LOTS OF DATA which would cause you to run out of CONTEXT\n- Make INCREMENTAL, SMALL, AND TARGETED tool calls for exploration\n- In all tool call requests, use the `limit` parameter to limit results (<10)\n- Use pagination\n\n### Step 5: Task Generation\n\nAfter inspecting the content, create 10 human-readable questions:\n- An LLM should be able to answer these with the MCP server\n- Follow all question and answer guidelines above\n\n## Output Format\n\nEach QA pair consists of a question and an answer. The output should be an XML file with this structure:\n\n```xml\n<evaluation>\n   <qa_pair>\n      <question>Find the project created in Q2 2024 with the highest number of completed tasks. What is the project name?</question>\n      <answer>Website Redesign</answer>\n   </qa_pair>\n   <qa_pair>\n      <question>Search for issues labeled as \"bug\" that were closed in March 2024. Which user closed the most issues? Provide their username.</question>\n      <answer>sarah_dev</answer>\n   </qa_pair>\n   <qa_pair>\n      <question>Look for pull requests that modified files in the /api directory and were merged between January 1 and January 31, 2024. How many different contributors worked on these PRs?</question>\n      <answer>7</answer>\n   </qa_pair>\n   <qa_pair>\n      <question>Find the repository with the most stars that was created before 2023. What is the repository name?</question>\n      <answer>data-pipeline</answer>\n   </qa_pair>\n</evaluation>\n```\n\n## Evaluation Examples\n\n### Good Questions\n\n**Example 1: Multi-hop question requiring deep exploration (GitHub MCP)**\n```xml\n<qa_pair>\n   <question>Find the repository that was archived in Q3 2023 and had previously been the most forked project in the organization. What was the primary programming language used in that repository?</question>\n   <answer>Python</answer>\n</qa_pair>\n```\n\nThis question is good because:\n- Requires multiple searches to find archived repositories\n- Needs to identify which had the most forks before archival\n- Requires examining repository details for the language\n- Answer is a simple, verifiable value\n- Based on historical (closed) data that won't change\n\n**Example 2: Requires understanding context without keyword matching (Project Management MCP)**\n```xml\n<qa_pair>\n   <question>Locate the initiative focused on improving customer onboarding that was completed in late 2023. The project lead created a retrospective document after completion. What was the lead's role title at that time?</question>\n   <answer>Product Manager</answer>\n</qa_pair>\n```\n\nThis question is good because:\n- Doesn't use specific project name (\"initiative focused on improving customer onboarding\")\n- Requires finding completed projects from specific timeframe\n- Needs to identify the project lead and their role\n- Requires understanding context from retrospective documents\n- Answer is human-readable and stable\n- Based on completed work (won't change)\n\n**Example 3: Complex aggregation requiring multiple steps (Issue Tracker MCP)**\n```xml\n<qa_pair>\n   <question>Among all bugs reported in January 2024 that were marked as critical priority, which assignee resolved the highest percentage of their assigned bugs within 48 hours? Provide the assignee's username.</question>\n   <answer>alex_eng</answer>\n</qa_pair>\n```\n\nThis question is good because:\n- Requires filtering bugs by date, priority, and status\n- Needs to group by assignee and calculate resolution rates\n- Requires understanding timestamps to determine 48-hour windows\n- Tests pagination (potentially many bugs to process)\n- Answer is a single username\n- Based on historical data from specific time period\n\n**Example 4: Requires synthesis across multiple data types (CRM MCP)**\n```xml\n<qa_pair>\n   <question>Find the account that upgraded from the Starter to Enterprise plan in Q4 2023 and had the highest annual contract value. What industry does this account operate in?</question>\n   <answer>Healthcare</answer>\n</qa_pair>\n```\n\nThis question is good because:\n- Requires understanding subscription tier changes\n- Needs to identify upgrade events in specific timeframe\n- Requires comparing contract values\n- Must access account industry information\n- Answer is simple and verifiable\n- Based on completed historical transactions\n\n### Poor Questions\n\n**Example 1: Answer changes over time**\n```xml\n<qa_pair>\n   <question>How many open issues are currently assigned to the engineering team?</question>\n   <answer>47</answer>\n</qa_pair>\n```\n\nThis question is poor because:\n- The answer will change as issues are created, closed, or reassigned\n- Not based on stable/stationary data\n- Relies on \"current state\" which is dynamic\n\n**Example 2: Too easy with keyword search**\n```xml\n<qa_pair>\n   <question>Find the pull request with title \"Add authentication feature\" and tell me who created it.</question>\n   <answer>developer123</answer>\n</qa_pair>\n```\n\nThis question is poor because:\n- Can be solved with a straightforward keyword search for exact title\n- Doesn't require deep exploration or understanding\n- No synthesis or analysis needed\n\n**Example 3: Ambiguous answer format**\n```xml\n<qa_pair>\n   <question>List all the repositories that have Python as their primary language.</question>\n   <answer>repo1, repo2, repo3, data-pipeline, ml-tools</answer>\n</qa_pair>\n```\n\nThis question is poor because:\n- Answer is a list that could be returned in any order\n- Difficult to verify with direct string comparison\n- LLM might format differently (JSON array, comma-separated, newline-separated)\n- Better to ask for a specific aggregate (count) or superlative (most stars)\n\n## Verification Process\n\nAfter creating evaluations:\n\n1. **Examine the XML file** to understand the schema\n2. **Load each task instruction** and in parallel using the MCP server and tools, identify the correct answer by attempting to solve the task YOURSELF\n3. **Flag any operations** that require WRITE or DESTRUCTIVE operations\n4. **Accumulate all CORRECT answers** and replace any incorrect answers in the document\n5. **Remove any `<qa_pair>`** that require WRITE or DESTRUCTIVE operations\n\nRemember to parallelize solving tasks to avoid running out of context, then accumulate all answers and make changes to the file at the end.\n\n## Tips for Creating Quality Evaluations\n\n1. **Think Hard and Plan Ahead** before generating tasks\n2. **Parallelize Where Opportunity Arises** to speed up the process and manage context\n3. **Focus on Realistic Use Cases** that humans would actually want to accomplish\n4. **Create Challenging Questions** that test the limits of the MCP server's capabilities\n5. **Ensure Stability** by using historical data and closed concepts\n6. **Verify Answers** by solving the questions yourself using the MCP server tools\n7. **Iterate and Refine** based on what you learn during the process\n\n---\n\n# Running Evaluations\n\nAfter creating your evaluation file, you can use the provided evaluation harness to test your MCP server.\n\n## Setup\n\n1. **Install Dependencies**\n\n   ```bash\n   pip install -r scripts/requirements.txt\n   ```\n\n   Or install manually:\n   ```bash\n   pip install anthropic mcp\n   ```\n\n2. **Set API Key**\n\n   ```bash\n   export ANTHROPIC_API_KEY=your_api_key_here\n   ```\n\n## Evaluation File Format\n\nEvaluation files use XML format with `<qa_pair>` elements:\n\n```xml\n<evaluation>\n   <qa_pair>\n      <question>Find the project created in Q2 2024 with the highest number of completed tasks. What is the project name?</question>\n      <answer>Website Redesign</answer>\n   </qa_pair>\n   <qa_pair>\n      <question>Search for issues labeled as \"bug\" that were closed in March 2024. Which user closed the most issues? Provide their username.</question>\n      <answer>sarah_dev</answer>\n   </qa_pair>\n</evaluation>\n```\n\n## Running Evaluations\n\nThe evaluation script (`scripts/evaluation.py`) supports three transport types:\n\n**Important:**\n- **stdio transport**: The evaluation script automatically launches and manages the MCP server process for you. Do not run the server manually.\n- **sse/http transports**: You must start the MCP server separately before running the evaluation. The script connects to the already-running server at the specified URL.\n\n### 1. Local STDIO Server\n\nFor locally-run MCP servers (script launches the server automatically):\n\n```bash\npython scripts/evaluation.py \\\n  -t stdio \\\n  -c python \\\n  -a my_mcp_server.py \\\n  evaluation.xml\n```\n\nWith environment variables:\n```bash\npython scripts/evaluation.py \\\n  -t stdio \\\n  -c python \\\n  -a my_mcp_server.py \\\n  -e API_KEY=abc123 \\\n  -e DEBUG=true \\\n  evaluation.xml\n```\n\n### 2. Server-Sent Events (SSE)\n\nFor SSE-based MCP servers (you must start the server first):\n\n```bash\npython scripts/evaluation.py \\\n  -t sse \\\n  -u https://example.com/mcp \\\n  -H \"Authorization: Bearer token123\" \\\n  -H \"X-Custom-Header: value\" \\\n  evaluation.xml\n```\n\n### 3. HTTP (Streamable HTTP)\n\nFor HTTP-based MCP servers (you must start the server first):\n\n```bash\npython scripts/evaluation.py \\\n  -t http \\\n  -u https://example.com/mcp \\\n  -H \"Authorization: Bearer token123\" \\\n  evaluation.xml\n```\n\n## Command-Line Options\n\n```\nusage: evaluation.py [-h] [-t {stdio,sse,http}] [-m MODEL] [-c COMMAND]\n                     [-a ARGS [ARGS ...]] [-e ENV [ENV ...]] [-u URL]\n                     [-H HEADERS [HEADERS ...]] [-o OUTPUT]\n                     eval_file\n\npositional arguments:\n  eval_file             Path to evaluation XML file\n\noptional arguments:\n  -h, --help            Show help message\n  -t, --transport       Transport type: stdio, sse, or http (default: stdio)\n  -m, --model           Claude model to use (default: claude-3-7-sonnet-20250219)\n  -o, --output          Output file for report (default: print to stdout)\n\nstdio options:\n  -c, --command         Command to run MCP server (e.g., python, node)\n  -a, --args            Arguments for the command (e.g., server.py)\n  -e, --env             Environment variables in KEY=VALUE format\n\nsse/http options:\n  -u, --url             MCP server URL\n  -H, --header          HTTP headers in 'Key: Value' format\n```\n\n## Output\n\nThe evaluation script generates a detailed report including:\n\n- **Summary Statistics**:\n  - Accuracy (correct/total)\n  - Average task duration\n  - Average tool calls per task\n  - Total tool calls\n\n- **Per-Task Results**:\n  - Prompt and expected response\n  - Actual response from the agent\n  - Whether the answer was correct (✅/❌)\n  - Duration and tool call details\n  - Agent's summary of its approach\n  - Agent's feedback on the tools\n\n### Save Report to File\n\n```bash\npython scripts/evaluation.py \\\n  -t stdio \\\n  -c python \\\n  -a my_server.py \\\n  -o evaluation_report.md \\\n  evaluation.xml\n```\n\n## Complete Example Workflow\n\nHere's a complete example of creating and running an evaluation:\n\n1. **Create your evaluation file** (`my_evaluation.xml`):\n\n```xml\n<evaluation>\n   <qa_pair>\n      <question>Find the user who created the most issues in January 2024. What is their username?</question>\n      <answer>alice_developer</answer>\n   </qa_pair>\n   <qa_pair>\n      <question>Among all pull requests merged in Q1 2024, which repository had the highest number? Provide the repository name.</question>\n      <answer>backend-api</answer>\n   </qa_pair>\n   <qa_pair>\n      <question>Find the project that was completed in December 2023 and had the longest duration from start to finish. How many days did it take?</question>\n      <answer>127</answer>\n   </qa_pair>\n</evaluation>\n```\n\n2. **Install dependencies**:\n\n```bash\npip install -r scripts/requirements.txt\nexport ANTHROPIC_API_KEY=your_api_key\n```\n\n3. **Run evaluation**:\n\n```bash\npython scripts/evaluation.py \\\n  -t stdio \\\n  -c python \\\n  -a github_mcp_server.py \\\n  -e GITHUB_TOKEN=ghp_xxx \\\n  -o github_eval_report.md \\\n  my_evaluation.xml\n```\n\n4. **Review the report** in `github_eval_report.md` to:\n   - See which questions passed/failed\n   - Read the agent's feedback on your tools\n   - Identify areas for improvement\n   - Iterate on your MCP server design\n\n## Troubleshooting\n\n### Connection Errors\n\nIf you get connection errors:\n- **STDIO**: Verify the command and arguments are correct\n- **SSE/HTTP**: Check the URL is accessible and headers are correct\n- Ensure any required API keys are set in environment variables or headers\n\n### Low Accuracy\n\nIf many evaluations fail:\n- Review the agent's feedback for each task\n- Check if tool descriptions are clear and comprehensive\n- Verify input parameters are well-documented\n- Consider whether tools return too much or too little data\n- Ensure error messages are actionable\n\n### Timeout Issues\n\nIf tasks are timing out:\n- Use a more capable model (e.g., `claude-3-7-sonnet-20250219`)\n- Check if tools are returning too much data\n- Verify pagination is working correctly\n- Consider simplifying complex questions\n\n<!-- File: core/skills/builtin/mcp-builder/reference/mcp_best_practices.md (Tokens: ~1593 | Category: anthropic-skill) -->\n# MCP Server Best Practices\n\n## Quick Reference\n\n### Server Naming\n- **Python**: `{service}_mcp` (e.g., `slack_mcp`)\n- **Node/TypeScript**: `{service}-mcp-server` (e.g., `slack-mcp-server`)\n\n### Tool Naming\n- Use snake_case with service prefix\n- Format: `{service}_{action}_{resource}`\n- Example: `slack_send_message`, `github_create_issue`\n\n### Response Formats\n- Support both JSON and Markdown formats\n- JSON for programmatic processing\n- Markdown for human readability\n\n### Pagination\n- Always respect `limit` parameter\n- Return `has_more`, `next_offset`, `total_count`\n- Default to 20-50 items\n\n### Transport\n- **Streamable HTTP**: For remote servers, multi-client scenarios\n- **stdio**: For local integrations, command-line tools\n- Avoid SSE (deprecated in favor of streamable HTTP)\n\n---\n\n## Server Naming Conventions\n\nFollow these standardized naming patterns:\n\n**Python**: Use format `{service}_mcp` (lowercase with underscores)\n- Examples: `slack_mcp`, `github_mcp`, `jira_mcp`\n\n**Node/TypeScript**: Use format `{service}-mcp-server` (lowercase with hyphens)\n- Examples: `slack-mcp-server`, `github-mcp-server`, `jira-mcp-server`\n\nThe name should be general, descriptive of the service being integrated, easy to infer from the task description, and without version numbers.\n\n---\n\n## Tool Naming and Design\n\n### Tool Naming\n\n1. **Use snake_case**: `search_users`, `create_project`, `get_channel_info`\n2. **Include service prefix**: Anticipate that your MCP server may be used alongside other MCP servers\n   - Use `slack_send_message` instead of just `send_message`\n   - Use `github_create_issue` instead of just `create_issue`\n3. **Be action-oriented**: Start with verbs (get, list, search, create, etc.)\n4. **Be specific**: Avoid generic names that could conflict with other servers\n\n### Tool Design\n\n- Tool descriptions must narrowly and unambiguously describe functionality\n- Descriptions must precisely match actual functionality\n- Provide tool annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint)\n- Keep tool operations focused and atomic\n\n---\n\n## Response Formats\n\nAll tools that return data should support multiple formats:\n\n### JSON Format (`response_format=\"json\"`)\n- Machine-readable structured data\n- Include all available fields and metadata\n- Consistent field names and types\n- Use for programmatic processing\n\n### Markdown Format (`response_format=\"markdown\"`, typically default)\n- Human-readable formatted text\n- Use headers, lists, and formatting for clarity\n- Convert timestamps to human-readable format\n- Show display names with IDs in parentheses\n- Omit verbose metadata\n\n---\n\n## Pagination\n\nFor tools that list resources:\n\n- **Always respect the `limit` parameter**\n- **Implement pagination**: Use `offset` or cursor-based pagination\n- **Return pagination metadata**: Include `has_more`, `next_offset`/`next_cursor`, `total_count`\n- **Never load all results into memory**: Especially important for large datasets\n- **Default to reasonable limits**: 20-50 items is typical\n\nExample pagination response:\n```json\n{\n  \"total\": 150,\n  \"count\": 20,\n  \"offset\": 0,\n  \"items\": [...],\n  \"has_more\": true,\n  \"next_offset\": 20\n}\n```\n\n---\n\n## Transport Options\n\n### Streamable HTTP\n\n**Best for**: Remote servers, web services, multi-client scenarios\n\n**Characteristics**:\n- Bidirectional communication over HTTP\n- Supports multiple simultaneous clients\n- Can be deployed as a web service\n- Enables server-to-client notifications\n\n**Use when**:\n- Serving multiple clients simultaneously\n- Deploying as a cloud service\n- Integration with web applications\n\n### stdio\n\n**Best for**: Local integrations, command-line tools\n\n**Characteristics**:\n- Standard input/output stream communication\n- Simple setup, no network configuration needed\n- Runs as a subprocess of the client\n\n**Use when**:\n- Building tools for local development environments\n- Integrating with desktop applications\n- Single-user, single-session scenarios\n\n**Note**: stdio servers should NOT log to stdout (use stderr for logging)\n\n### Transport Selection\n\n| Criterion | stdio | Streamable HTTP |\n|-----------|-------|-----------------|\n| **Deployment** | Local | Remote |\n| **Clients** | Single | Multiple |\n| **Complexity** | Low | Medium |\n| **Real-time** | No | Yes |\n\n---\n\n## Security Best Practices\n\n### Authentication and Authorization\n\n**OAuth 2.1**:\n- Use secure OAuth 2.1 with certificates from recognized authorities\n- Validate access tokens before processing requests\n- Only accept tokens specifically intended for your server\n\n**API Keys**:\n- Store API keys in environment variables, never in code\n- Validate keys on server startup\n- Provide clear error messages when authentication fails\n\n### Input Validation\n\n- Sanitize file paths to prevent directory traversal\n- Validate URLs and external identifiers\n- Check parameter sizes and ranges\n- Prevent command injection in system calls\n- Use schema validation (Pydantic/Zod) for all inputs\n\n### Error Handling\n\n- Don't expose internal errors to clients\n- Log security-relevant errors server-side\n- Provide helpful but not revealing error messages\n- Clean up resources after errors\n\n### DNS Rebinding Protection\n\nFor streamable HTTP servers running locally:\n- Enable DNS rebinding protection\n- Validate the `Origin` header on all incoming connections\n- Bind to `127.0.0.1` rather than `0.0.0.0`\n\n---\n\n## Tool Annotations\n\nProvide annotations to help clients understand tool behavior:\n\n| Annotation | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `readOnlyHint` | boolean | false | Tool does not modify its environment |\n| `destructiveHint` | boolean | true | Tool may perform destructive updates |\n| `idempotentHint` | boolean | false | Repeated calls with same args have no additional effect |\n| `openWorldHint` | boolean | true | Tool interacts with external entities |\n\n**Important**: Annotations are hints, not security guarantees. Clients should not make security-critical decisions based solely on annotations.\n\n---\n\n## Error Handling\n\n- Use standard JSON-RPC error codes\n- Report tool errors within result objects (not protocol-level errors)\n- Provide helpful, specific error messages with suggested next steps\n- Don't expose internal implementation details\n- Clean up resources properly on errors\n\nExample error handling:\n```typescript\ntry {\n  const result = performOperation();\n  return { content: [{ type: \"text\", text: result }] };\n} catch (error) {\n  return {\n    isError: true,\n    content: [{\n      type: \"text\",\n      text: `Error: ${error.message}. Try using filter='active_only' to reduce results.`\n    }]\n  };\n}\n```\n\n---\n\n## Testing Requirements\n\nComprehensive testing should cover:\n\n- **Functional testing**: Verify correct execution with valid/invalid inputs\n- **Integration testing**: Test interaction with external systems\n- **Security testing**: Validate auth, input sanitization, rate limiting\n- **Performance testing**: Check behavior under load, timeouts\n- **Error handling**: Ensure proper error reporting and cleanup\n\n---\n\n## Documentation Requirements\n\n- Provide clear documentation of all tools and capabilities\n- Include working examples (at least 3 per major feature)\n- Document security considerations\n- Specify required permissions and access levels\n- Document rate limits and performance characteristics\n\n<!-- File: core/skills/builtin/mcp-builder/reference/node_mcp_server.md (Tokens: ~6582 | Category: anthropic-skill) -->\n# Node/TypeScript MCP Server Implementation Guide\n\n## Overview\n\nThis document provides Node/TypeScript-specific best practices and examples for implementing MCP servers using the MCP TypeScript SDK. It covers project structure, server setup, tool registration patterns, input validation with Zod, error handling, and complete working examples.\n\n---\n\n## Quick Reference\n\n### Key Imports\n```typescript\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport express from \"express\";\nimport { z } from \"zod\";\n```\n\n### Server Initialization\n```typescript\nconst server = new McpServer({\n  name: \"service-mcp-server\",\n  version: \"1.0.0\"\n});\n```\n\n### Tool Registration Pattern\n```typescript\nserver.registerTool(\n  \"tool_name\",\n  {\n    title: \"Tool Display Name\",\n    description: \"What the tool does\",\n    inputSchema: { param: z.string() },\n    outputSchema: { result: z.string() }\n  },\n  async ({ param }) => {\n    const output = { result: `Processed: ${param}` };\n    return {\n      content: [{ type: \"text\", text: JSON.stringify(output) }],\n      structuredContent: output // Modern pattern for structured data\n    };\n  }\n);\n```\n\n---\n\n## MCP TypeScript SDK\n\nThe official MCP TypeScript SDK provides:\n- `McpServer` class for server initialization\n- `registerTool` method for tool registration\n- Zod schema integration for runtime input validation\n- Type-safe tool handler implementations\n\n**IMPORTANT - Use Modern APIs Only:**\n- **DO use**: `server.registerTool()`, `server.registerResource()`, `server.registerPrompt()`\n- **DO NOT use**: Old deprecated APIs such as `server.tool()`, `server.setRequestHandler(ListToolsRequestSchema, ...)`, or manual handler registration\n- The `register*` methods provide better type safety, automatic schema handling, and are the recommended approach\n\nSee the MCP SDK documentation in the references for complete details.\n\n## Server Naming Convention\n\nNode/TypeScript MCP servers must follow this naming pattern:\n- **Format**: `{service}-mcp-server` (lowercase with hyphens)\n- **Examples**: `github-mcp-server`, `jira-mcp-server`, `stripe-mcp-server`\n\nThe name should be:\n- General (not tied to specific features)\n- Descriptive of the service/API being integrated\n- Easy to infer from the task description\n- Without version numbers or dates\n\n## Project Structure\n\nCreate the following structure for Node/TypeScript MCP servers:\n\n```\n{service}-mcp-server/\n├── package.json\n├── tsconfig.json\n├── README.md\n├── src/\n│   ├── index.ts          # Main entry point with McpServer initialization\n│   ├── types.ts          # TypeScript type definitions and interfaces\n│   ├── tools/            # Tool implementations (one file per domain)\n│   ├── services/         # API clients and shared utilities\n│   ├── schemas/          # Zod validation schemas\n│   └── constants.ts      # Shared constants (API_URL, CHARACTER_LIMIT, etc.)\n└── dist/                 # Built JavaScript files (entry point: dist/index.js)\n```\n\n## Tool Implementation\n\n### Tool Naming\n\nUse snake_case for tool names (e.g., \"search_users\", \"create_project\", \"get_channel_info\") with clear, action-oriented names.\n\n**Avoid Naming Conflicts**: Include the service context to prevent overlaps:\n- Use \"slack_send_message\" instead of just \"send_message\"\n- Use \"github_create_issue\" instead of just \"create_issue\"\n- Use \"asana_list_tasks\" instead of just \"list_tasks\"\n\n### Tool Structure\n\nTools are registered using the `registerTool` method with the following requirements:\n- Use Zod schemas for runtime input validation and type safety\n- The `description` field must be explicitly provided - JSDoc comments are NOT automatically extracted\n- Explicitly provide `title`, `description`, `inputSchema`, and `annotations`\n- The `inputSchema` must be a Zod schema object (not a JSON schema)\n- Type all parameters and return values explicitly\n\n```typescript\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\n\nconst server = new McpServer({\n  name: \"example-mcp\",\n  version: \"1.0.0\"\n});\n\n// Zod schema for input validation\nconst UserSearchInputSchema = z.object({\n  query: z.string()\n    .min(2, \"Query must be at least 2 characters\")\n    .max(200, \"Query must not exceed 200 characters\")\n    .describe(\"Search string to match against names/emails\"),\n  limit: z.number()\n    .int()\n    .min(1)\n    .max(100)\n    .default(20)\n    .describe(\"Maximum results to return\"),\n  offset: z.number()\n    .int()\n    .min(0)\n    .default(0)\n    .describe(\"Number of results to skip for pagination\"),\n  response_format: z.nativeEnum(ResponseFormat)\n    .default(ResponseFormat.MARKDOWN)\n    .describe(\"Output format: 'markdown' for human-readable or 'json' for machine-readable\")\n}).strict();\n\n// Type definition from Zod schema\ntype UserSearchInput = z.infer<typeof UserSearchInputSchema>;\n\nserver.registerTool(\n  \"example_search_users\",\n  {\n    title: \"Search Example Users\",\n    description: `Search for users in the Example system by name, email, or team.\n\nThis tool searches across all user profiles in the Example platform, supporting partial matches and various search filters. It does NOT create or modify users, only searches existing ones.\n\nArgs:\n  - query (string): Search string to match against names/emails\n  - limit (number): Maximum results to return, between 1-100 (default: 20)\n  - offset (number): Number of results to skip for pagination (default: 0)\n  - response_format ('markdown' | 'json'): Output format (default: 'markdown')\n\nReturns:\n  For JSON format: Structured data with schema:\n  {\n    \"total\": number,           // Total number of matches found\n    \"count\": number,           // Number of results in this response\n    \"offset\": number,          // Current pagination offset\n    \"users\": [\n      {\n        \"id\": string,          // User ID (e.g., \"U123456789\")\n        \"name\": string,        // Full name (e.g., \"John Doe\")\n        \"email\": string,       // Email address\n        \"team\": string,        // Team name (optional)\n        \"active\": boolean      // Whether user is active\n      }\n    ],\n    \"has_more\": boolean,       // Whether more results are available\n    \"next_offset\": number      // Offset for next page (if has_more is true)\n  }\n\nExamples:\n  - Use when: \"Find all marketing team members\" -> params with query=\"team:marketing\"\n  - Use when: \"Search for John's account\" -> params with query=\"john\"\n  - Don't use when: You need to create a user (use example_create_user instead)\n\nError Handling:\n  - Returns \"Error: Rate limit exceeded\" if too many requests (429 status)\n  - Returns \"No users found matching '<query>'\" if search returns empty`,\n    inputSchema: UserSearchInputSchema,\n    annotations: {\n      readOnlyHint: true,\n      destructiveHint: false,\n      idempotentHint: true,\n      openWorldHint: true\n    }\n  },\n  async (params: UserSearchInput) => {\n    try {\n      // Input validation is handled by Zod schema\n      // Make API request using validated parameters\n      const data = await makeApiRequest<any>(\n        \"users/search\",\n        \"GET\",\n        undefined,\n        {\n          q: params.query,\n          limit: params.limit,\n          offset: params.offset\n        }\n      );\n\n      const users = data.users || [];\n      const total = data.total || 0;\n\n      if (!users.length) {\n        return {\n          content: [{\n            type: \"text\",\n            text: `No users found matching '${params.query}'`\n          }]\n        };\n      }\n\n      // Prepare structured output\n      const output = {\n        total,\n        count: users.length,\n        offset: params.offset,\n        users: users.map((user: any) => ({\n          id: user.id,\n          name: user.name,\n          email: user.email,\n          ...(user.team ? { team: user.team } : {}),\n          active: user.active ?? true\n        })),\n        has_more: total > params.offset + users.length,\n        ...(total > params.offset + users.length ? {\n          next_offset: params.offset + users.length\n        } : {})\n      };\n\n      // Format text representation based on requested format\n      let textContent: string;\n      if (params.response_format === ResponseFormat.MARKDOWN) {\n        const lines = [`# User Search Results: '${params.query}'`, \"\",\n          `Found ${total} users (showing ${users.length})`, \"\"];\n        for (const user of users) {\n          lines.push(`## ${user.name} (${user.id})`);\n          lines.push(`- **Email**: ${user.email}`);\n          if (user.team) lines.push(`- **Team**: ${user.team}`);\n          lines.push(\"\");\n        }\n        textContent = lines.join(\"\\n\");\n      } else {\n        textContent = JSON.stringify(output, null, 2);\n      }\n\n      return {\n        content: [{ type: \"text\", text: textContent }],\n        structuredContent: output // Modern pattern for structured data\n      };\n    } catch (error) {\n      return {\n        content: [{\n          type: \"text\",\n          text: handleApiError(error)\n        }]\n      };\n    }\n  }\n);\n```\n\n## Zod Schemas for Input Validation\n\nZod provides runtime type validation:\n\n```typescript\nimport { z } from \"zod\";\n\n// Basic schema with validation\nconst CreateUserSchema = z.object({\n  name: z.string()\n    .min(1, \"Name is required\")\n    .max(100, \"Name must not exceed 100 characters\"),\n  email: z.string()\n    .email(\"Invalid email format\"),\n  age: z.number()\n    .int(\"Age must be a whole number\")\n    .min(0, \"Age cannot be negative\")\n    .max(150, \"Age cannot be greater than 150\")\n}).strict();  // Use .strict() to forbid extra fields\n\n// Enums\nenum ResponseFormat {\n  MARKDOWN = \"markdown\",\n  JSON = \"json\"\n}\n\nconst SearchSchema = z.object({\n  response_format: z.nativeEnum(ResponseFormat)\n    .default(ResponseFormat.MARKDOWN)\n    .describe(\"Output format\")\n});\n\n// Optional fields with defaults\nconst PaginationSchema = z.object({\n  limit: z.number()\n    .int()\n    .min(1)\n    .max(100)\n    .default(20)\n    .describe(\"Maximum results to return\"),\n  offset: z.number()\n    .int()\n    .min(0)\n    .default(0)\n    .describe(\"Number of results to skip\")\n});\n```\n\n## Response Format Options\n\nSupport multiple output formats for flexibility:\n\n```typescript\nenum ResponseFormat {\n  MARKDOWN = \"markdown\",\n  JSON = \"json\"\n}\n\nconst inputSchema = z.object({\n  query: z.string(),\n  response_format: z.nativeEnum(ResponseFormat)\n    .default(ResponseFormat.MARKDOWN)\n    .describe(\"Output format: 'markdown' for human-readable or 'json' for machine-readable\")\n});\n```\n\n**Markdown format**:\n- Use headers, lists, and formatting for clarity\n- Convert timestamps to human-readable format\n- Show display names with IDs in parentheses\n- Omit verbose metadata\n- Group related information logically\n\n**JSON format**:\n- Return complete, structured data suitable for programmatic processing\n- Include all available fields and metadata\n- Use consistent field names and types\n\n## Pagination Implementation\n\nFor tools that list resources:\n\n```typescript\nconst ListSchema = z.object({\n  limit: z.number().int().min(1).max(100).default(20),\n  offset: z.number().int().min(0).default(0)\n});\n\nasync function listItems(params: z.infer<typeof ListSchema>) {\n  const data = await apiRequest(params.limit, params.offset);\n\n  const response = {\n    total: data.total,\n    count: data.items.length,\n    offset: params.offset,\n    items: data.items,\n    has_more: data.total > params.offset + data.items.length,\n    next_offset: data.total > params.offset + data.items.length\n      ? params.offset + data.items.length\n      : undefined\n  };\n\n  return JSON.stringify(response, null, 2);\n}\n```\n\n## Character Limits and Truncation\n\nAdd a CHARACTER_LIMIT constant to prevent overwhelming responses:\n\n```typescript\n// At module level in constants.ts\nexport const CHARACTER_LIMIT = 25000;  // Maximum response size in characters\n\nasync function searchTool(params: SearchInput) {\n  let result = generateResponse(data);\n\n  // Check character limit and truncate if needed\n  if (result.length > CHARACTER_LIMIT) {\n    const truncatedData = data.slice(0, Math.max(1, data.length / 2));\n    response.data = truncatedData;\n    response.truncated = true;\n    response.truncation_message =\n      `Response truncated from ${data.length} to ${truncatedData.length} items. ` +\n      `Use 'offset' parameter or add filters to see more results.`;\n    result = JSON.stringify(response, null, 2);\n  }\n\n  return result;\n}\n```\n\n## Error Handling\n\nProvide clear, actionable error messages:\n\n```typescript\nimport axios, { AxiosError } from \"axios\";\n\nfunction handleApiError(error: unknown): string {\n  if (error instanceof AxiosError) {\n    if (error.response) {\n      switch (error.response.status) {\n        case 404:\n          return \"Error: Resource not found. Please check the ID is correct.\";\n        case 403:\n          return \"Error: Permission denied. You don't have access to this resource.\";\n        case 429:\n          return \"Error: Rate limit exceeded. Please wait before making more requests.\";\n        default:\n          return `Error: API request failed with status ${error.response.status}`;\n      }\n    } else if (error.code === \"ECONNABORTED\") {\n      return \"Error: Request timed out. Please try again.\";\n    }\n  }\n  return `Error: Unexpected error occurred: ${error instanceof Error ? error.message : String(error)}`;\n}\n```\n\n## Shared Utilities\n\nExtract common functionality into reusable functions:\n\n```typescript\n// Shared API request function\nasync function makeApiRequest<T>(\n  endpoint: string,\n  method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" = \"GET\",\n  data?: any,\n  params?: any\n): Promise<T> {\n  try {\n    const response = await axios({\n      method,\n      url: `${API_BASE_URL}/${endpoint}`,\n      data,\n      params,\n      timeout: 30000,\n      headers: {\n        \"Content-Type\": \"application/json\",\n        \"Accept\": \"application/json\"\n      }\n    });\n    return response.data;\n  } catch (error) {\n    throw error;\n  }\n}\n```\n\n## Async/Await Best Practices\n\nAlways use async/await for network requests and I/O operations:\n\n```typescript\n// Good: Async network request\nasync function fetchData(resourceId: string): Promise<ResourceData> {\n  const response = await axios.get(`${API_URL}/resource/${resourceId}`);\n  return response.data;\n}\n\n// Bad: Promise chains\nfunction fetchData(resourceId: string): Promise<ResourceData> {\n  return axios.get(`${API_URL}/resource/${resourceId}`)\n    .then(response => response.data);  // Harder to read and maintain\n}\n```\n\n## TypeScript Best Practices\n\n1. **Use Strict TypeScript**: Enable strict mode in tsconfig.json\n2. **Define Interfaces**: Create clear interface definitions for all data structures\n3. **Avoid `any`**: Use proper types or `unknown` instead of `any`\n4. **Zod for Runtime Validation**: Use Zod schemas to validate external data\n5. **Type Guards**: Create type guard functions for complex type checking\n6. **Error Handling**: Always use try-catch with proper error type checking\n7. **Null Safety**: Use optional chaining (`?.`) and nullish coalescing (`??`)\n\n```typescript\n// Good: Type-safe with Zod and interfaces\ninterface UserResponse {\n  id: string;\n  name: string;\n  email: string;\n  team?: string;\n  active: boolean;\n}\n\nconst UserSchema = z.object({\n  id: z.string(),\n  name: z.string(),\n  email: z.string().email(),\n  team: z.string().optional(),\n  active: z.boolean()\n});\n\ntype User = z.infer<typeof UserSchema>;\n\nasync function getUser(id: string): Promise<User> {\n  const data = await apiCall(`/users/${id}`);\n  return UserSchema.parse(data);  // Runtime validation\n}\n\n// Bad: Using any\nasync function getUser(id: string): Promise<any> {\n  return await apiCall(`/users/${id}`);  // No type safety\n}\n```\n\n## Package Configuration\n\n### package.json\n\n```json\n{\n  \"name\": \"{service}-mcp-server\",\n  \"version\": \"1.0.0\",\n  \"description\": \"MCP server for {Service} API integration\",\n  \"type\": \"module\",\n  \"main\": \"dist/index.js\",\n  \"scripts\": {\n    \"start\": \"node dist/index.js\",\n    \"dev\": \"tsx watch src/index.ts\",\n    \"build\": \"tsc\",\n    \"clean\": \"rm -rf dist\"\n  },\n  \"engines\": {\n    \"node\": \">=18\"\n  },\n  \"dependencies\": {\n    \"@modelcontextprotocol/sdk\": \"^1.6.1\",\n    \"axios\": \"^1.7.9\",\n    \"zod\": \"^3.23.8\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.10.0\",\n    \"tsx\": \"^4.19.2\",\n    \"typescript\": \"^5.7.2\"\n  }\n}\n```\n\n### tsconfig.json\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"Node16\",\n    \"moduleResolution\": \"Node16\",\n    \"lib\": [\"ES2022\"],\n    \"outDir\": \"./dist\",\n    \"rootDir\": \"./src\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"declaration\": true,\n    \"declarationMap\": true,\n    \"sourceMap\": true,\n    \"allowSyntheticDefaultImports\": true\n  },\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"node_modules\", \"dist\"]\n}\n```\n\n## Complete Example\n\n```typescript\n#!/usr/bin/env node\n/**\n * MCP Server for Example Service.\n *\n * This server provides tools to interact with Example API, including user search,\n * project management, and data export capabilities.\n */\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport axios, { AxiosError } from \"axios\";\n\n// Constants\nconst API_BASE_URL = \"https://api.example.com/v1\";\nconst CHARACTER_LIMIT = 25000;\n\n// Enums\nenum ResponseFormat {\n  MARKDOWN = \"markdown\",\n  JSON = \"json\"\n}\n\n// Zod schemas\nconst UserSearchInputSchema = z.object({\n  query: z.string()\n    .min(2, \"Query must be at least 2 characters\")\n    .max(200, \"Query must not exceed 200 characters\")\n    .describe(\"Search string to match against names/emails\"),\n  limit: z.number()\n    .int()\n    .min(1)\n    .max(100)\n    .default(20)\n    .describe(\"Maximum results to return\"),\n  offset: z.number()\n    .int()\n    .min(0)\n    .default(0)\n    .describe(\"Number of results to skip for pagination\"),\n  response_format: z.nativeEnum(ResponseFormat)\n    .default(ResponseFormat.MARKDOWN)\n    .describe(\"Output format: 'markdown' for human-readable or 'json' for machine-readable\")\n}).strict();\n\ntype UserSearchInput = z.infer<typeof UserSearchInputSchema>;\n\n// Shared utility functions\nasync function makeApiRequest<T>(\n  endpoint: string,\n  method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" = \"GET\",\n  data?: any,\n  params?: any\n): Promise<T> {\n  try {\n    const response = await axios({\n      method,\n      url: `${API_BASE_URL}/${endpoint}`,\n      data,\n      params,\n      timeout: 30000,\n      headers: {\n        \"Content-Type\": \"application/json\",\n        \"Accept\": \"application/json\"\n      }\n    });\n    return response.data;\n  } catch (error) {\n    throw error;\n  }\n}\n\nfunction handleApiError(error: unknown): string {\n  if (error instanceof AxiosError) {\n    if (error.response) {\n      switch (error.response.status) {\n        case 404:\n          return \"Error: Resource not found. Please check the ID is correct.\";\n        case 403:\n          return \"Error: Permission denied. You don't have access to this resource.\";\n        case 429:\n          return \"Error: Rate limit exceeded. Please wait before making more requests.\";\n        default:\n          return `Error: API request failed with status ${error.response.status}`;\n      }\n    } else if (error.code === \"ECONNABORTED\") {\n      return \"Error: Request timed out. Please try again.\";\n    }\n  }\n  return `Error: Unexpected error occurred: ${error instanceof Error ? error.message : String(error)}`;\n}\n\n// Create MCP server instance\nconst server = new McpServer({\n  name: \"example-mcp\",\n  version: \"1.0.0\"\n});\n\n// Register tools\nserver.registerTool(\n  \"example_search_users\",\n  {\n    title: \"Search Example Users\",\n    description: `[Full description as shown above]`,\n    inputSchema: UserSearchInputSchema,\n    annotations: {\n      readOnlyHint: true,\n      destructiveHint: false,\n      idempotentHint: true,\n      openWorldHint: true\n    }\n  },\n  async (params: UserSearchInput) => {\n    // Implementation as shown above\n  }\n);\n\n// Main function\n// For stdio (local):\nasync function runStdio() {\n  if (!process.env.EXAMPLE_API_KEY) {\n    console.error(\"ERROR: EXAMPLE_API_KEY environment variable is required\");\n    process.exit(1);\n  }\n\n  const transport = new StdioServerTransport();\n  await server.connect(transport);\n  console.error(\"MCP server running via stdio\");\n}\n\n// For streamable HTTP (remote):\nasync function runHTTP() {\n  if (!process.env.EXAMPLE_API_KEY) {\n    console.error(\"ERROR: EXAMPLE_API_KEY environment variable is required\");\n    process.exit(1);\n  }\n\n  const app = express();\n  app.use(express.json());\n\n  app.post('/mcp', async (req, res) => {\n    const transport = new StreamableHTTPServerTransport({\n      sessionIdGenerator: undefined,\n      enableJsonResponse: true\n    });\n    res.on('close', () => transport.close());\n    await server.connect(transport);\n    await transport.handleRequest(req, res, req.body);\n  });\n\n  const port = parseInt(process.env.PORT || '3000');\n  app.listen(port, () => {\n    console.error(`MCP server running on http://localhost:${port}/mcp`);\n  });\n}\n\n// Choose transport based on environment\nconst transport = process.env.TRANSPORT || 'stdio';\nif (transport === 'http') {\n  runHTTP().catch(error => {\n    console.error(\"Server error:\", error);\n    process.exit(1);\n  });\n} else {\n  runStdio().catch(error => {\n    console.error(\"Server error:\", error);\n    process.exit(1);\n  });\n}\n```\n\n---\n\n## Advanced MCP Features\n\n### Resource Registration\n\nExpose data as resources for efficient, URI-based access:\n\n```typescript\nimport { ResourceTemplate } from \"@modelcontextprotocol/sdk/types.js\";\n\n// Register a resource with URI template\nserver.registerResource(\n  {\n    uri: \"file://documents/{name}\",\n    name: \"Document Resource\",\n    description: \"Access documents by name\",\n    mimeType: \"text/plain\"\n  },\n  async (uri: string) => {\n    // Extract parameter from URI\n    const match = uri.match(/^file:\\/\\/documents\\/(.+)$/);\n    if (!match) {\n      throw new Error(\"Invalid URI format\");\n    }\n\n    const documentName = match[1];\n    const content = await loadDocument(documentName);\n\n    return {\n      contents: [{\n        uri,\n        mimeType: \"text/plain\",\n        text: content\n      }]\n    };\n  }\n);\n\n// List available resources dynamically\nserver.registerResourceList(async () => {\n  const documents = await getAvailableDocuments();\n  return {\n    resources: documents.map(doc => ({\n      uri: `file://documents/${doc.name}`,\n      name: doc.name,\n      mimeType: \"text/plain\",\n      description: doc.description\n    }))\n  };\n});\n```\n\n**When to use Resources vs Tools:**\n- **Resources**: For data access with simple URI-based parameters\n- **Tools**: For complex operations requiring validation and business logic\n- **Resources**: When data is relatively static or template-based\n- **Tools**: When operations have side effects or complex workflows\n\n### Transport Options\n\nThe TypeScript SDK supports two main transport mechanisms:\n\n#### Streamable HTTP (Recommended for Remote Servers)\n\n```typescript\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport express from \"express\";\n\nconst app = express();\napp.use(express.json());\n\napp.post('/mcp', async (req, res) => {\n  // Create new transport for each request (stateless, prevents request ID collisions)\n  const transport = new StreamableHTTPServerTransport({\n    sessionIdGenerator: undefined,\n    enableJsonResponse: true\n  });\n\n  res.on('close', () => transport.close());\n\n  await server.connect(transport);\n  await transport.handleRequest(req, res, req.body);\n});\n\napp.listen(3000);\n```\n\n#### stdio (For Local Integrations)\n\n```typescript\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n```\n\n**Transport selection:**\n- **Streamable HTTP**: Web services, remote access, multiple clients\n- **stdio**: Command-line tools, local development, subprocess integration\n\n### Notification Support\n\nNotify clients when server state changes:\n\n```typescript\n// Notify when tools list changes\nserver.notification({\n  method: \"notifications/tools/list_changed\"\n});\n\n// Notify when resources change\nserver.notification({\n  method: \"notifications/resources/list_changed\"\n});\n```\n\nUse notifications sparingly - only when server capabilities genuinely change.\n\n---\n\n## Code Best Practices\n\n### Code Composability and Reusability\n\nYour implementation MUST prioritize composability and code reuse:\n\n1. **Extract Common Functionality**:\n   - Create reusable helper functions for operations used across multiple tools\n   - Build shared API clients for HTTP requests instead of duplicating code\n   - Centralize error handling logic in utility functions\n   - Extract business logic into dedicated functions that can be composed\n   - Extract shared markdown or JSON field selection & formatting functionality\n\n2. **Avoid Duplication**:\n   - NEVER copy-paste similar code between tools\n   - If you find yourself writing similar logic twice, extract it into a function\n   - Common operations like pagination, filtering, field selection, and formatting should be shared\n   - Authentication/authorization logic should be centralized\n\n## Building and Running\n\nAlways build your TypeScript code before running:\n\n```bash\n# Build the project\nnpm run build\n\n# Run the server\nnpm start\n\n# Development with auto-reload\nnpm run dev\n```\n\nAlways ensure `npm run build` completes successfully before considering the implementation complete.\n\n## Quality Checklist\n\nBefore finalizing your Node/TypeScript MCP server implementation, ensure:\n\n### Strategic Design\n- [ ] Tools enable complete workflows, not just API endpoint wrappers\n- [ ] Tool names reflect natural task subdivisions\n- [ ] Response formats optimize for agent context efficiency\n- [ ] Human-readable identifiers used where appropriate\n- [ ] Error messages guide agents toward correct usage\n\n### Implementation Quality\n- [ ] FOCUSED IMPLEMENTATION: Most important and valuable tools implemented\n- [ ] All tools registered using `registerTool` with complete configuration\n- [ ] All tools include `title`, `description`, `inputSchema`, and `annotations`\n- [ ] Annotations correctly set (readOnlyHint, destructiveHint, idempotentHint, openWorldHint)\n- [ ] All tools use Zod schemas for runtime input validation with `.strict()` enforcement\n- [ ] All Zod schemas have proper constraints and descriptive error messages\n- [ ] All tools have comprehensive descriptions with explicit input/output types\n- [ ] Descriptions include return value examples and complete schema documentation\n- [ ] Error messages are clear, actionable, and educational\n\n### TypeScript Quality\n- [ ] TypeScript interfaces are defined for all data structures\n- [ ] Strict TypeScript is enabled in tsconfig.json\n- [ ] No use of `any` type - use `unknown` or proper types instead\n- [ ] All async functions have explicit Promise<T> return types\n- [ ] Error handling uses proper type guards (e.g., `axios.isAxiosError`, `z.ZodError`)\n\n### Advanced Features (where applicable)\n- [ ] Resources registered for appropriate data endpoints\n- [ ] Appropriate transport configured (stdio or streamable HTTP)\n- [ ] Notifications implemented for dynamic server capabilities\n- [ ] Type-safe with SDK interfaces\n\n### Project Configuration\n- [ ] Package.json includes all necessary dependencies\n- [ ] Build script produces working JavaScript in dist/ directory\n- [ ] Main entry point is properly configured as dist/index.js\n- [ ] Server name follows format: `{service}-mcp-server`\n- [ ] tsconfig.json properly configured with strict mode\n\n### Code Quality\n- [ ] Pagination is properly implemented where applicable\n- [ ] Large responses check CHARACTER_LIMIT constant and truncate with clear messages\n- [ ] Filtering options are provided for potentially large result sets\n- [ ] All network operations handle timeouts and connection errors gracefully\n- [ ] Common functionality is extracted into reusable functions\n- [ ] Return types are consistent across similar operations\n\n### Testing and Build\n- [ ] `npm run build` completes successfully without errors\n- [ ] dist/index.js created and executable\n- [ ] Server runs: `node dist/index.js --help`\n- [ ] All imports resolve correctly\n- [ ] Sample tool calls work as expected\n\n<!-- File: core/skills/builtin/mcp-builder/reference/python_mcp_server.md (Tokens: ~5525 | Category: anthropic-skill) -->\n# Python MCP Server Implementation Guide\n\n## Overview\n\nThis document provides Python-specific best practices and examples for implementing MCP servers using the MCP Python SDK. It covers server setup, tool registration patterns, input validation with Pydantic, error handling, and complete working examples.\n\n---\n\n## Quick Reference\n\n### Key Imports\n```python\nfrom mcp.server.fastmcp import FastMCP\nfrom pydantic import BaseModel, Field, field_validator, ConfigDict\nfrom typing import Optional, List, Dict, Any\nfrom enum import Enum\nimport httpx\n```\n\n### Server Initialization\n```python\nmcp = FastMCP(\"service_mcp\")\n```\n\n### Tool Registration Pattern\n```python\n@mcp.tool(name=\"tool_name\", annotations={...})\nasync def tool_function(params: InputModel) -> str:\n    # Implementation\n    pass\n```\n\n---\n\n## MCP Python SDK and FastMCP\n\nThe official MCP Python SDK provides FastMCP, a high-level framework for building MCP servers. It provides:\n- Automatic description and inputSchema generation from function signatures and docstrings\n- Pydantic model integration for input validation\n- Decorator-based tool registration with `@mcp.tool`\n\n**For complete SDK documentation, use WebFetch to load:**\n`https://raw.githubusercontent.com/modelcontextprotocol/python-sdk/main/README.md`\n\n## Server Naming Convention\n\nPython MCP servers must follow this naming pattern:\n- **Format**: `{service}_mcp` (lowercase with underscores)\n- **Examples**: `github_mcp`, `jira_mcp`, `stripe_mcp`\n\nThe name should be:\n- General (not tied to specific features)\n- Descriptive of the service/API being integrated\n- Easy to infer from the task description\n- Without version numbers or dates\n\n## Tool Implementation\n\n### Tool Naming\n\nUse snake_case for tool names (e.g., \"search_users\", \"create_project\", \"get_channel_info\") with clear, action-oriented names.\n\n**Avoid Naming Conflicts**: Include the service context to prevent overlaps:\n- Use \"slack_send_message\" instead of just \"send_message\"\n- Use \"github_create_issue\" instead of just \"create_issue\"\n- Use \"asana_list_tasks\" instead of just \"list_tasks\"\n\n### Tool Structure with FastMCP\n\nTools are defined using the `@mcp.tool` decorator with Pydantic models for input validation:\n\n```python\nfrom pydantic import BaseModel, Field, ConfigDict\nfrom mcp.server.fastmcp import FastMCP\n\n# Initialize the MCP server\nmcp = FastMCP(\"example_mcp\")\n\n# Define Pydantic model for input validation\nclass ServiceToolInput(BaseModel):\n    '''Input model for service tool operation.'''\n    model_config = ConfigDict(\n        str_strip_whitespace=True,  # Auto-strip whitespace from strings\n        validate_assignment=True,    # Validate on assignment\n        extra='forbid'              # Forbid extra fields\n    )\n\n    param1: str = Field(..., description=\"First parameter description (e.g., 'user123', 'project-abc')\", min_length=1, max_length=100)\n    param2: Optional[int] = Field(default=None, description=\"Optional integer parameter with constraints\", ge=0, le=1000)\n    tags: Optional[List[str]] = Field(default_factory=list, description=\"List of tags to apply\", max_items=10)\n\n@mcp.tool(\n    name=\"service_tool_name\",\n    annotations={\n        \"title\": \"Human-Readable Tool Title\",\n        \"readOnlyHint\": True,     # Tool does not modify environment\n        \"destructiveHint\": False,  # Tool does not perform destructive operations\n        \"idempotentHint\": True,    # Repeated calls have no additional effect\n        \"openWorldHint\": False     # Tool does not interact with external entities\n    }\n)\nasync def service_tool_name(params: ServiceToolInput) -> str:\n    '''Tool description automatically becomes the 'description' field.\n\n    This tool performs a specific operation on the service. It validates all inputs\n    using the ServiceToolInput Pydantic model before processing.\n\n    Args:\n        params (ServiceToolInput): Validated input parameters containing:\n            - param1 (str): First parameter description\n            - param2 (Optional[int]): Optional parameter with default\n            - tags (Optional[List[str]]): List of tags\n\n    Returns:\n        str: JSON-formatted response containing operation results\n    '''\n    # Implementation here\n    pass\n```\n\n## Pydantic v2 Key Features\n\n- Use `model_config` instead of nested `Config` class\n- Use `field_validator` instead of deprecated `validator`\n- Use `model_dump()` instead of deprecated `dict()`\n- Validators require `@classmethod` decorator\n- Type hints are required for validator methods\n\n```python\nfrom pydantic import BaseModel, Field, field_validator, ConfigDict\n\nclass CreateUserInput(BaseModel):\n    model_config = ConfigDict(\n        str_strip_whitespace=True,\n        validate_assignment=True\n    )\n\n    name: str = Field(..., description=\"User's full name\", min_length=1, max_length=100)\n    email: str = Field(..., description=\"User's email address\", pattern=r'^[\\w\\.-]+@[\\w\\.-]+\\.\\w+$')\n    age: int = Field(..., description=\"User's age\", ge=0, le=150)\n\n    @field_validator('email')\n    @classmethod\n    def validate_email(cls, v: str) -> str:\n        if not v.strip():\n            raise ValueError(\"Email cannot be empty\")\n        return v.lower()\n```\n\n## Response Format Options\n\nSupport multiple output formats for flexibility:\n\n```python\nfrom enum import Enum\n\nclass ResponseFormat(str, Enum):\n    '''Output format for tool responses.'''\n    MARKDOWN = \"markdown\"\n    JSON = \"json\"\n\nclass UserSearchInput(BaseModel):\n    query: str = Field(..., description=\"Search query\")\n    response_format: ResponseFormat = Field(\n        default=ResponseFormat.MARKDOWN,\n        description=\"Output format: 'markdown' for human-readable or 'json' for machine-readable\"\n    )\n```\n\n**Markdown format**:\n- Use headers, lists, and formatting for clarity\n- Convert timestamps to human-readable format (e.g., \"2024-01-15 10:30:00 UTC\" instead of epoch)\n- Show display names with IDs in parentheses (e.g., \"@john.doe (U123456)\")\n- Omit verbose metadata (e.g., show only one profile image URL, not all sizes)\n- Group related information logically\n\n**JSON format**:\n- Return complete, structured data suitable for programmatic processing\n- Include all available fields and metadata\n- Use consistent field names and types\n\n## Pagination Implementation\n\nFor tools that list resources:\n\n```python\nclass ListInput(BaseModel):\n    limit: Optional[int] = Field(default=20, description=\"Maximum results to return\", ge=1, le=100)\n    offset: Optional[int] = Field(default=0, description=\"Number of results to skip for pagination\", ge=0)\n\nasync def list_items(params: ListInput) -> str:\n    # Make API request with pagination\n    data = await api_request(limit=params.limit, offset=params.offset)\n\n    # Return pagination info\n    response = {\n        \"total\": data[\"total\"],\n        \"count\": len(data[\"items\"]),\n        \"offset\": params.offset,\n        \"items\": data[\"items\"],\n        \"has_more\": data[\"total\"] > params.offset + len(data[\"items\"]),\n        \"next_offset\": params.offset + len(data[\"items\"]) if data[\"total\"] > params.offset + len(data[\"items\"]) else None\n    }\n    return json.dumps(response, indent=2)\n```\n\n## Error Handling\n\nProvide clear, actionable error messages:\n\n```python\ndef _handle_api_error(e: Exception) -> str:\n    '''Consistent error formatting across all tools.'''\n    if isinstance(e, httpx.HTTPStatusError):\n        if e.response.status_code == 404:\n            return \"Error: Resource not found. Please check the ID is correct.\"\n        elif e.response.status_code == 403:\n            return \"Error: Permission denied. You don't have access to this resource.\"\n        elif e.response.status_code == 429:\n            return \"Error: Rate limit exceeded. Please wait before making more requests.\"\n        return f\"Error: API request failed with status {e.response.status_code}\"\n    elif isinstance(e, httpx.TimeoutException):\n        return \"Error: Request timed out. Please try again.\"\n    return f\"Error: Unexpected error occurred: {type(e).__name__}\"\n```\n\n## Shared Utilities\n\nExtract common functionality into reusable functions:\n\n```python\n# Shared API request function\nasync def _make_api_request(endpoint: str, method: str = \"GET\", **kwargs) -> dict:\n    '''Reusable function for all API calls.'''\n    async with httpx.AsyncClient() as client:\n        response = await client.request(\n            method,\n            f\"{API_BASE_URL}/{endpoint}\",\n            timeout=30.0,\n            **kwargs\n        )\n        response.raise_for_status()\n        return response.json()\n```\n\n## Async/Await Best Practices\n\nAlways use async/await for network requests and I/O operations:\n\n```python\n# Good: Async network request\nasync def fetch_data(resource_id: str) -> dict:\n    async with httpx.AsyncClient() as client:\n        response = await client.get(f\"{API_URL}/resource/{resource_id}\")\n        response.raise_for_status()\n        return response.json()\n\n# Bad: Synchronous request\ndef fetch_data(resource_id: str) -> dict:\n    response = requests.get(f\"{API_URL}/resource/{resource_id}\")  # Blocks\n    return response.json()\n```\n\n## Type Hints\n\nUse type hints throughout:\n\n```python\nfrom typing import Optional, List, Dict, Any\n\nasync def get_user(user_id: str) -> Dict[str, Any]:\n    data = await fetch_user(user_id)\n    return {\"id\": data[\"id\"], \"name\": data[\"name\"]}\n```\n\n## Tool Docstrings\n\nEvery tool must have comprehensive docstrings with explicit type information:\n\n```python\nasync def search_users(params: UserSearchInput) -> str:\n    '''\n    Search for users in the Example system by name, email, or team.\n\n    This tool searches across all user profiles in the Example platform,\n    supporting partial matches and various search filters. It does NOT\n    create or modify users, only searches existing ones.\n\n    Args:\n        params (UserSearchInput): Validated input parameters containing:\n            - query (str): Search string to match against names/emails (e.g., \"john\", \"@example.com\", \"team:marketing\")\n            - limit (Optional[int]): Maximum results to return, between 1-100 (default: 20)\n            - offset (Optional[int]): Number of results to skip for pagination (default: 0)\n\n    Returns:\n        str: JSON-formatted string containing search results with the following schema:\n\n        Success response:\n        {\n            \"total\": int,           # Total number of matches found\n            \"count\": int,           # Number of results in this response\n            \"offset\": int,          # Current pagination offset\n            \"users\": [\n                {\n                    \"id\": str,      # User ID (e.g., \"U123456789\")\n                    \"name\": str,    # Full name (e.g., \"John Doe\")\n                    \"email\": str,   # Email address (e.g., \"john@example.com\")\n                    \"team\": str     # Team name (e.g., \"Marketing\") - optional\n                }\n            ]\n        }\n\n        Error response:\n        \"Error: <error message>\" or \"No users found matching '<query>'\"\n\n    Examples:\n        - Use when: \"Find all marketing team members\" -> params with query=\"team:marketing\"\n        - Use when: \"Search for John's account\" -> params with query=\"john\"\n        - Don't use when: You need to create a user (use example_create_user instead)\n        - Don't use when: You have a user ID and need full details (use example_get_user instead)\n\n    Error Handling:\n        - Input validation errors are handled by Pydantic model\n        - Returns \"Error: Rate limit exceeded\" if too many requests (429 status)\n        - Returns \"Error: Invalid API authentication\" if API key is invalid (401 status)\n        - Returns formatted list of results or \"No users found matching 'query'\"\n    '''\n```\n\n## Complete Example\n\nSee below for a complete Python MCP server example:\n\n```python\n#!/usr/bin/env python3\n'''\nMCP Server for Example Service.\n\nThis server provides tools to interact with Example API, including user search,\nproject management, and data export capabilities.\n'''\n\nfrom typing import Optional, List, Dict, Any\nfrom enum import Enum\nimport httpx\nfrom pydantic import BaseModel, Field, field_validator, ConfigDict\nfrom mcp.server.fastmcp import FastMCP\n\n# Initialize the MCP server\nmcp = FastMCP(\"example_mcp\")\n\n# Constants\nAPI_BASE_URL = \"https://api.example.com/v1\"\n\n# Enums\nclass ResponseFormat(str, Enum):\n    '''Output format for tool responses.'''\n    MARKDOWN = \"markdown\"\n    JSON = \"json\"\n\n# Pydantic Models for Input Validation\nclass UserSearchInput(BaseModel):\n    '''Input model for user search operations.'''\n    model_config = ConfigDict(\n        str_strip_whitespace=True,\n        validate_assignment=True\n    )\n\n    query: str = Field(..., description=\"Search string to match against names/emails\", min_length=2, max_length=200)\n    limit: Optional[int] = Field(default=20, description=\"Maximum results to return\", ge=1, le=100)\n    offset: Optional[int] = Field(default=0, description=\"Number of results to skip for pagination\", ge=0)\n    response_format: ResponseFormat = Field(default=ResponseFormat.MARKDOWN, description=\"Output format\")\n\n    @field_validator('query')\n    @classmethod\n    def validate_query(cls, v: str) -> str:\n        if not v.strip():\n            raise ValueError(\"Query cannot be empty or whitespace only\")\n        return v.strip()\n\n# Shared utility functions\nasync def _make_api_request(endpoint: str, method: str = \"GET\", **kwargs) -> dict:\n    '''Reusable function for all API calls.'''\n    async with httpx.AsyncClient() as client:\n        response = await client.request(\n            method,\n            f\"{API_BASE_URL}/{endpoint}\",\n            timeout=30.0,\n            **kwargs\n        )\n        response.raise_for_status()\n        return response.json()\n\ndef _handle_api_error(e: Exception) -> str:\n    '''Consistent error formatting across all tools.'''\n    if isinstance(e, httpx.HTTPStatusError):\n        if e.response.status_code == 404:\n            return \"Error: Resource not found. Please check the ID is correct.\"\n        elif e.response.status_code == 403:\n            return \"Error: Permission denied. You don't have access to this resource.\"\n        elif e.response.status_code == 429:\n            return \"Error: Rate limit exceeded. Please wait before making more requests.\"\n        return f\"Error: API request failed with status {e.response.status_code}\"\n    elif isinstance(e, httpx.TimeoutException):\n        return \"Error: Request timed out. Please try again.\"\n    return f\"Error: Unexpected error occurred: {type(e).__name__}\"\n\n# Tool definitions\n@mcp.tool(\n    name=\"example_search_users\",\n    annotations={\n        \"title\": \"Search Example Users\",\n        \"readOnlyHint\": True,\n        \"destructiveHint\": False,\n        \"idempotentHint\": True,\n        \"openWorldHint\": True\n    }\n)\nasync def example_search_users(params: UserSearchInput) -> str:\n    '''Search for users in the Example system by name, email, or team.\n\n    [Full docstring as shown above]\n    '''\n    try:\n        # Make API request using validated parameters\n        data = await _make_api_request(\n            \"users/search\",\n            params={\n                \"q\": params.query,\n                \"limit\": params.limit,\n                \"offset\": params.offset\n            }\n        )\n\n        users = data.get(\"users\", [])\n        total = data.get(\"total\", 0)\n\n        if not users:\n            return f\"No users found matching '{params.query}'\"\n\n        # Format response based on requested format\n        if params.response_format == ResponseFormat.MARKDOWN:\n            lines = [f\"# User Search Results: '{params.query}'\", \"\"]\n            lines.append(f\"Found {total} users (showing {len(users)})\")\n            lines.append(\"\")\n\n            for user in users:\n                lines.append(f\"## {user['name']} ({user['id']})\")\n                lines.append(f\"- **Email**: {user['email']}\")\n                if user.get('team'):\n                    lines.append(f\"- **Team**: {user['team']}\")\n                lines.append(\"\")\n\n            return \"\\n\".join(lines)\n\n        else:\n            # Machine-readable JSON format\n            import json\n            response = {\n                \"total\": total,\n                \"count\": len(users),\n                \"offset\": params.offset,\n                \"users\": users\n            }\n            return json.dumps(response, indent=2)\n\n    except Exception as e:\n        return _handle_api_error(e)\n\nif __name__ == \"__main__\":\n    mcp.run()\n```\n\n---\n\n## Advanced FastMCP Features\n\n### Context Parameter Injection\n\nFastMCP can automatically inject a `Context` parameter into tools for advanced capabilities like logging, progress reporting, resource reading, and user interaction:\n\n```python\nfrom mcp.server.fastmcp import FastMCP, Context\n\nmcp = FastMCP(\"example_mcp\")\n\n@mcp.tool()\nasync def advanced_search(query: str, ctx: Context) -> str:\n    '''Advanced tool with context access for logging and progress.'''\n\n    # Report progress for long operations\n    await ctx.report_progress(0.25, \"Starting search...\")\n\n    # Log information for debugging\n    await ctx.log_info(\"Processing query\", {\"query\": query, \"timestamp\": datetime.now()})\n\n    # Perform search\n    results = await search_api(query)\n    await ctx.report_progress(0.75, \"Formatting results...\")\n\n    # Access server configuration\n    server_name = ctx.fastmcp.name\n\n    return format_results(results)\n\n@mcp.tool()\nasync def interactive_tool(resource_id: str, ctx: Context) -> str:\n    '''Tool that can request additional input from users.'''\n\n    # Request sensitive information when needed\n    api_key = await ctx.elicit(\n        prompt=\"Please provide your API key:\",\n        input_type=\"password\"\n    )\n\n    # Use the provided key\n    return await api_call(resource_id, api_key)\n```\n\n**Context capabilities:**\n- `ctx.report_progress(progress, message)` - Report progress for long operations\n- `ctx.log_info(message, data)` / `ctx.log_error()` / `ctx.log_debug()` - Logging\n- `ctx.elicit(prompt, input_type)` - Request input from users\n- `ctx.fastmcp.name` - Access server configuration\n- `ctx.read_resource(uri)` - Read MCP resources\n\n### Resource Registration\n\nExpose data as resources for efficient, template-based access:\n\n```python\n@mcp.resource(\"file://documents/{name}\")\nasync def get_document(name: str) -> str:\n    '''Expose documents as MCP resources.\n\n    Resources are useful for static or semi-static data that doesn't\n    require complex parameters. They use URI templates for flexible access.\n    '''\n    document_path = f\"./docs/{name}\"\n    with open(document_path, \"r\") as f:\n        return f.read()\n\n@mcp.resource(\"config://settings/{key}\")\nasync def get_setting(key: str, ctx: Context) -> str:\n    '''Expose configuration as resources with context.'''\n    settings = await load_settings()\n    return json.dumps(settings.get(key, {}))\n```\n\n**When to use Resources vs Tools:**\n- **Resources**: For data access with simple parameters (URI templates)\n- **Tools**: For complex operations with validation and business logic\n\n### Structured Output Types\n\nFastMCP supports multiple return types beyond strings:\n\n```python\nfrom typing import TypedDict\nfrom dataclasses import dataclass\nfrom pydantic import BaseModel\n\n# TypedDict for structured returns\nclass UserData(TypedDict):\n    id: str\n    name: str\n    email: str\n\n@mcp.tool()\nasync def get_user_typed(user_id: str) -> UserData:\n    '''Returns structured data - FastMCP handles serialization.'''\n    return {\"id\": user_id, \"name\": \"John Doe\", \"email\": \"john@example.com\"}\n\n# Pydantic models for complex validation\nclass DetailedUser(BaseModel):\n    id: str\n    name: str\n    email: str\n    created_at: datetime\n    metadata: Dict[str, Any]\n\n@mcp.tool()\nasync def get_user_detailed(user_id: str) -> DetailedUser:\n    '''Returns Pydantic model - automatically generates schema.'''\n    user = await fetch_user(user_id)\n    return DetailedUser(**user)\n```\n\n### Lifespan Management\n\nInitialize resources that persist across requests:\n\n```python\nfrom contextlib import asynccontextmanager\n\n@asynccontextmanager\nasync def app_lifespan():\n    '''Manage resources that live for the server's lifetime.'''\n    # Initialize connections, load config, etc.\n    db = await connect_to_database()\n    config = load_configuration()\n\n    # Make available to all tools\n    yield {\"db\": db, \"config\": config}\n\n    # Cleanup on shutdown\n    await db.close()\n\nmcp = FastMCP(\"example_mcp\", lifespan=app_lifespan)\n\n@mcp.tool()\nasync def query_data(query: str, ctx: Context) -> str:\n    '''Access lifespan resources through context.'''\n    db = ctx.request_context.lifespan_state[\"db\"]\n    results = await db.query(query)\n    return format_results(results)\n```\n\n### Transport Options\n\nFastMCP supports two main transport mechanisms:\n\n```python\n# stdio transport (for local tools) - default\nif __name__ == \"__main__\":\n    mcp.run()\n\n# Streamable HTTP transport (for remote servers)\nif __name__ == \"__main__\":\n    mcp.run(transport=\"streamable_http\", port=8000)\n```\n\n**Transport selection:**\n- **stdio**: Command-line tools, local integrations, subprocess execution\n- **Streamable HTTP**: Web services, remote access, multiple clients\n\n---\n\n## Code Best Practices\n\n### Code Composability and Reusability\n\nYour implementation MUST prioritize composability and code reuse:\n\n1. **Extract Common Functionality**:\n   - Create reusable helper functions for operations used across multiple tools\n   - Build shared API clients for HTTP requests instead of duplicating code\n   - Centralize error handling logic in utility functions\n   - Extract business logic into dedicated functions that can be composed\n   - Extract shared markdown or JSON field selection & formatting functionality\n\n2. **Avoid Duplication**:\n   - NEVER copy-paste similar code between tools\n   - If you find yourself writing similar logic twice, extract it into a function\n   - Common operations like pagination, filtering, field selection, and formatting should be shared\n   - Authentication/authorization logic should be centralized\n\n### Python-Specific Best Practices\n\n1. **Use Type Hints**: Always include type annotations for function parameters and return values\n2. **Pydantic Models**: Define clear Pydantic models for all input validation\n3. **Avoid Manual Validation**: Let Pydantic handle input validation with constraints\n4. **Proper Imports**: Group imports (standard library, third-party, local)\n5. **Error Handling**: Use specific exception types (httpx.HTTPStatusError, not generic Exception)\n6. **Async Context Managers**: Use `async with` for resources that need cleanup\n7. **Constants**: Define module-level constants in UPPER_CASE\n\n## Quality Checklist\n\nBefore finalizing your Python MCP server implementation, ensure:\n\n### Strategic Design\n- [ ] Tools enable complete workflows, not just API endpoint wrappers\n- [ ] Tool names reflect natural task subdivisions\n- [ ] Response formats optimize for agent context efficiency\n- [ ] Human-readable identifiers used where appropriate\n- [ ] Error messages guide agents toward correct usage\n\n### Implementation Quality\n- [ ] FOCUSED IMPLEMENTATION: Most important and valuable tools implemented\n- [ ] All tools have descriptive names and documentation\n- [ ] Return types are consistent across similar operations\n- [ ] Error handling is implemented for all external calls\n- [ ] Server name follows format: `{service}_mcp`\n- [ ] All network operations use async/await\n- [ ] Common functionality is extracted into reusable functions\n- [ ] Error messages are clear, actionable, and educational\n- [ ] Outputs are properly validated and formatted\n\n### Tool Configuration\n- [ ] All tools implement 'name' and 'annotations' in the decorator\n- [ ] Annotations correctly set (readOnlyHint, destructiveHint, idempotentHint, openWorldHint)\n- [ ] All tools use Pydantic BaseModel for input validation with Field() definitions\n- [ ] All Pydantic Fields have explicit types and descriptions with constraints\n- [ ] All tools have comprehensive docstrings with explicit input/output types\n- [ ] Docstrings include complete schema structure for dict/JSON returns\n- [ ] Pydantic models handle input validation (no manual validation needed)\n\n### Advanced Features (where applicable)\n- [ ] Context injection used for logging, progress, or elicitation\n- [ ] Resources registered for appropriate data endpoints\n- [ ] Lifespan management implemented for persistent connections\n- [ ] Structured output types used (TypedDict, Pydantic models)\n- [ ] Appropriate transport configured (stdio or streamable HTTP)\n\n### Code Quality\n- [ ] File includes proper imports including Pydantic imports\n- [ ] Pagination is properly implemented where applicable\n- [ ] Filtering options are provided for potentially large result sets\n- [ ] All async functions are properly defined with `async def`\n- [ ] HTTP client usage follows async patterns with proper context managers\n- [ ] Type hints are used throughout the code\n- [ ] Constants are defined at module level in UPPER_CASE\n\n### Testing\n- [ ] Server runs successfully: `python your_server.py --help`\n- [ ] All imports resolve correctly\n- [ ] Sample tool calls work as expected\n- [ ] Error scenarios handled gracefully\n\n<!-- File: core/skills/builtin/mcp-builder/SKILL.md (Tokens: ~1922 | Category: anthropic-skill) -->\n---\nname: mcp-builder\ndescription: Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).\nlicense: Complete terms in LICENSE.txt\n---\n\n# MCP Server Development Guide\n\n## Overview\n\nCreate MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. The quality of an MCP server is measured by how well it enables LLMs to accomplish real-world tasks.\n\n---\n\n# Process\n\n## 🚀 High-Level Workflow\n\nCreating a high-quality MCP server involves four main phases:\n\n### Phase 1: Deep Research and Planning\n\n#### 1.1 Understand Modern MCP Design\n\n**API Coverage vs. Workflow Tools:**\nBalance comprehensive API endpoint coverage with specialized workflow tools. Workflow tools can be more convenient for specific tasks, while comprehensive coverage gives agents flexibility to compose operations. Performance varies by client—some clients benefit from code execution that combines basic tools, while others work better with higher-level workflows. When uncertain, prioritize comprehensive API coverage.\n\n**Tool Naming and Discoverability:**\nClear, descriptive tool names help agents find the right tools quickly. Use consistent prefixes (e.g., `github_create_issue`, `github_list_repos`) and action-oriented naming.\n\n**Context Management:**\nAgents benefit from concise tool descriptions and the ability to filter/paginate results. Design tools that return focused, relevant data. Some clients support code execution which can help agents filter and process data efficiently.\n\n**Actionable Error Messages:**\nError messages should guide agents toward solutions with specific suggestions and next steps.\n\n#### 1.2 Study MCP Protocol Documentation\n\n**Navigate the MCP specification:**\n\nStart with the sitemap to find relevant pages: `https://modelcontextprotocol.io/sitemap.xml`\n\nThen fetch specific pages with `.md` suffix for markdown format (e.g., `https://modelcontextprotocol.io/specification/draft.md`).\n\nKey pages to review:\n- Specification overview and architecture\n- Transport mechanisms (streamable HTTP, stdio)\n- Tool, resource, and prompt definitions\n\n#### 1.3 Study Framework Documentation\n\n**Recommended stack:**\n- **Language**: TypeScript (high-quality SDK support and good compatibility in many execution environments e.g. MCPB. Plus AI models are good at generating TypeScript code, benefiting from its broad usage, static typing and good linting tools)\n- **Transport**: Streamable HTTP for remote servers, using stateless JSON (simpler to scale and maintain, as opposed to stateful sessions and streaming responses). stdio for local servers.\n\n**Load framework documentation:**\n\n- **MCP Best Practices**: [📋 View Best Practices](./reference/mcp_best_practices.md) - Core guidelines\n\n**For TypeScript (recommended):**\n- **TypeScript SDK**: Use WebFetch to load `https://raw.githubusercontent.com/modelcontextprotocol/typescript-sdk/main/README.md`\n- [⚡ TypeScript Guide](./reference/node_mcp_server.md) - TypeScript patterns and examples\n\n**For Python:**\n- **Python SDK**: Use WebFetch to load `https://raw.githubusercontent.com/modelcontextprotocol/python-sdk/main/README.md`\n- [🐍 Python Guide](./reference/python_mcp_server.md) - Python patterns and examples\n\n#### 1.4 Plan Your Implementation\n\n**Understand the API:**\nReview the service's API documentation to identify key endpoints, authentication requirements, and data models. Use web search and WebFetch as needed.\n\n**Tool Selection:**\nPrioritize comprehensive API coverage. List endpoints to implement, starting with the most common operations.\n\n---\n\n### Phase 2: Implementation\n\n#### 2.1 Set Up Project Structure\n\nSee language-specific guides for project setup:\n- [⚡ TypeScript Guide](./reference/node_mcp_server.md) - Project structure, package.json, tsconfig.json\n- [🐍 Python Guide](./reference/python_mcp_server.md) - Module organization, dependencies\n\n#### 2.2 Implement Core Infrastructure\n\nCreate shared utilities:\n- API client with authentication\n- Error handling helpers\n- Response formatting (JSON/Markdown)\n- Pagination support\n\n#### 2.3 Implement Tools\n\nFor each tool:\n\n**Input Schema:**\n- Use Zod (TypeScript) or Pydantic (Python)\n- Include constraints and clear descriptions\n- Add examples in field descriptions\n\n**Output Schema:**\n- Define `outputSchema` where possible for structured data\n- Use `structuredContent` in tool responses (TypeScript SDK feature)\n- Helps clients understand and process tool outputs\n\n**Tool Description:**\n- Concise summary of functionality\n- Parameter descriptions\n- Return type schema\n\n**Implementation:**\n- Async/await for I/O operations\n- Proper error handling with actionable messages\n- Support pagination where applicable\n- Return both text content and structured data when using modern SDKs\n\n**Annotations:**\n- `readOnlyHint`: true/false\n- `destructiveHint`: true/false\n- `idempotentHint`: true/false\n- `openWorldHint`: true/false\n\n---\n\n### Phase 3: Review and Test\n\n#### 3.1 Code Quality\n\nReview for:\n- No duplicated code (DRY principle)\n- Consistent error handling\n- Full type coverage\n- Clear tool descriptions\n\n#### 3.2 Build and Test\n\n**TypeScript:**\n- Run `npm run build` to verify compilation\n- Test with MCP Inspector: `npx @modelcontextprotocol/inspector`\n\n**Python:**\n- Verify syntax: `python -m py_compile your_server.py`\n- Test with MCP Inspector\n\nSee language-specific guides for detailed testing approaches and quality checklists.\n\n---\n\n### Phase 4: Create Evaluations\n\nAfter implementing your MCP server, create comprehensive evaluations to test its effectiveness.\n\n**Load [✅ Evaluation Guide](./reference/evaluation.md) for complete evaluation guidelines.**\n\n#### 4.1 Understand Evaluation Purpose\n\nUse evaluations to test whether LLMs can effectively use your MCP server to answer realistic, complex questions.\n\n#### 4.2 Create 10 Evaluation Questions\n\nTo create effective evaluations, follow the process outlined in the evaluation guide:\n\n1. **Tool Inspection**: List available tools and understand their capabilities\n2. **Content Exploration**: Use READ-ONLY operations to explore available data\n3. **Question Generation**: Create 10 complex, realistic questions\n4. **Answer Verification**: Solve each question yourself to verify answers\n\n#### 4.3 Evaluation Requirements\n\nEnsure each question is:\n- **Independent**: Not dependent on other questions\n- **Read-only**: Only non-destructive operations required\n- **Complex**: Requiring multiple tool calls and deep exploration\n- **Realistic**: Based on real use cases humans would care about\n- **Verifiable**: Single, clear answer that can be verified by string comparison\n- **Stable**: Answer won't change over time\n\n#### 4.4 Output Format\n\nCreate an XML file with this structure:\n\n```xml\n<evaluation>\n  <qa_pair>\n    <question>Find discussions about AI model launches with animal codenames. One model needed a specific safety designation that uses the format ASL-X. What number X was being determined for the model named after a spotted wild cat?</question>\n    <answer>3</answer>\n  </qa_pair>\n<!-- More qa_pairs... -->\n</evaluation>\n```\n\n---\n\n# Reference Files\n\n## 📚 Documentation Library\n\nLoad these resources as needed during development:\n\n### Core MCP Documentation (Load First)\n- **MCP Protocol**: Start with sitemap at `https://modelcontextprotocol.io/sitemap.xml`, then fetch specific pages with `.md` suffix\n- [📋 MCP Best Practices](./reference/mcp_best_practices.md) - Universal MCP guidelines including:\n  - Server and tool naming conventions\n  - Response format guidelines (JSON vs Markdown)\n  - Pagination best practices\n  - Transport selection (streamable HTTP vs stdio)\n  - Security and error handling standards\n\n### SDK Documentation (Load During Phase 1/2)\n- **Python SDK**: Fetch from `https://raw.githubusercontent.com/modelcontextprotocol/python-sdk/main/README.md`\n- **TypeScript SDK**: Fetch from `https://raw.githubusercontent.com/modelcontextprotocol/typescript-sdk/main/README.md`\n\n### Language-Specific Implementation Guides (Load During Phase 2)\n- [🐍 Python Implementation Guide](./reference/python_mcp_server.md) - Complete Python/FastMCP guide with:\n  - Server initialization patterns\n  - Pydantic model examples\n  - Tool registration with `@mcp.tool`\n  - Complete working examples\n  - Quality checklist\n\n- [⚡ TypeScript Implementation Guide](./reference/node_mcp_server.md) - Complete TypeScript guide with:\n  - Project structure\n  - Zod schema patterns\n  - Tool registration with `server.registerTool`\n  - Complete working examples\n  - Quality checklist\n\n### Evaluation Guide (Load During Phase 4)\n- [✅ Evaluation Guide](./reference/evaluation.md) - Complete evaluation creation guide with:\n  - Question creation guidelines\n  - Answer verification strategies\n  - XML format specifications\n  - Example questions and answers\n  - Running an evaluation with the provided scripts\n\n<!-- File: core/skills/builtin/review-agent/agents/openai.yaml (Tokens: ~53 | Category: anthropic-skill) -->\ninterface:\n  display_name: \"Review Agent\"\n  short_description: \"Find actionable bugs in code changes\"\n  default_prompt: \"Use $review-agent to review the requested code changes and return actionable findings.\"\npolicy:\n  allow_implicit_invocation: false\n\n<!-- File: core/skills/builtin/review-agent/SKILL.md (Tokens: ~553 | Category: anthropic-skill) -->\n---\nname: review-agent\ndescription: Perform a read-only, defect-first review of a specified code change and return every actionable finding. Use when another agent delegates review of uncommitted changes, a base-branch diff, a commit, or custom review instructions.\n---\n\n# Review Agent\n\nInspect the requested target directly and return every finding that the author would likely fix.\nDo not modify files, create commits, push branches, post review comments, or delegate the review\nto another agent.\n\n## Review the change\n\n1. Read the applicable `AGENTS.md` instructions.\n2. Inspect the complete diff for the requested target and enough surrounding code to understand\n   each changed path.\n3. Identify concrete regressions introduced by the change. Continue through the whole diff after\n   finding the first issue.\n4. Check the relevant tests and call sites to confirm that each finding is real and actionable.\n\nFor a base-branch review, compare the changes that would actually merge rather than diffing\ndirectly against the branch tip. Resolve the comparison ref to the branch's upstream when that\nupstream exists and is ahead of the local branch; otherwise use the local branch. Run\n`git merge-base HEAD <comparison-ref>`, then inspect `git diff <merge-base-sha>`. If the local\nbranch cannot be resolved, try its configured upstream explicitly before reporting that the target\nis unavailable.\n\nFlag an issue only when all of these are true:\n\n- It affects correctness, security, performance, or maintainability in a meaningful way.\n- It is discrete and actionable.\n- It was introduced by the reviewed change.\n- The affected scenario or call path can be demonstrated from the code.\n- The author would probably fix it if they knew about it.\n\nDo not flag speculative concerns, pre-existing problems, intentional behavior changes, or style\nnits that do not obscure the code.\n\n## Write the result\n\nPresent findings first, ordered by severity. Use one entry per issue in this form:\n\n`[P1] Imperative finding title — path/to/file.rs:line`\n\nFollow the title with one short paragraph explaining the affected scenario and why the behavior is\nwrong. Keep the cited range as small as possible and make sure it overlaps the reviewed diff.\n\nUse these priorities:\n\n- `P0`: universal release blocker or critical failure.\n- `P1`: urgent defect that should be fixed next.\n- `P2`: ordinary defect that should be fixed.\n- `P3`: low-impact issue that is still worth fixing.\n\nIf there are no qualifying findings, say `No findings.` Do not invent a finding to fill the result.\nAfter the findings, add a brief overall assessment and mention any material test gaps or residual\nrisks.\n\n<!-- File: core/skills/builtin/security-best-practices/agents/openai.yaml (Tokens: ~44 | Category: anthropic-skill) -->\ninterface:\n  display_name: \"Security Best Practices\"\n  short_description: \"Security reviews and secure-by-default guidance\"\n  default_prompt: \"Review this codebase for security best practices and suggest secure-by-default improvements.\"\n\n<!-- File: core/skills/builtin/security-best-practices/references/golang-general-backend-security.md (Tokens: ~8580 | Category: anthropic-skill) -->\n# Go (Golang) Security Spec (Go 1.25.x, Standard Library, net/http)\n\nThis document is designed as a **security spec** that supports:\n1) **Secure-by-default code generation** for new Go code.\n2) **Security review / vulnerability hunting** in existing Go code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n--------------------------------------------------------------------\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n- MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session cookies, JWTs, database URLs with credentials, signing keys, client secrets).\n- MUST NOT “fix” security by disabling protections (e.g., `InsecureSkipVerify`, `GOSUMDB=off` for public modules, wildcard CORS + credentials, removing auth checks, disabling CSRF defenses on cookie-auth apps).\n- MUST provide **evidence-based findings** during audits: cite file paths, code snippets, build/deploy configs, and concrete values that justify the claim.\n- MUST treat uncertainty honestly: if a control might exist in infrastructure (reverse proxy, WAF, service mesh, platform config), report it as “not visible in app code; verify at runtime/config.”\n- MUST keep fixes minimal, correct, and production-safe; avoid introducing breaking changes without warning (especially around auth/session flows, and proxies).\n\n--------------------------------------------------------------------\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\nWhen asked to write new Go code or modify existing code:\n- MUST follow every **MUST** requirement in this spec.\n- SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n- MUST prefer safe-by-default APIs and proven libraries over custom security code.\n- MUST avoid introducing new risky sinks (shell execution, dynamic template execution, serving user files as HTML, unsafe redirects, weak crypto, unbounded parsing, etc.).\n\n### 1.2 Passive review mode (always on while editing)\nWhile working anywhere in a Go repo (even if the user did not ask for a security scan):\n- MUST “notice” violations of this spec in touched/nearby code.\n- SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n- MUST systematically search the codebase for violations of this spec.\n- MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n1) Build/deploy entrypoints: `main.go`, `cmd/*`, Dockerfiles, Kubernetes manifests, systemd units, CI workflows.\n2) Go toolchain & dependency policy: Go version, modules, `go.mod/go.sum`, proxy/sumdb settings, govulncheck usage.\n3) Secret management and config loading (env, files, secret stores) + logging patterns.\n4) HTTP server configuration (timeouts, body limits, proxy trust, security headers).\n5) AuthN/AuthZ boundaries, session/cookie settings, token validation.\n6) CSRF protections for cookie-authenticated state-changing endpoints.\n7) Template usage and output encoding (XSS), and any “render template from string” behavior (SSTI).\n8) File handling (uploads/downloads/path traversal/temp files), static file serving.\n9) Injection sinks: SQL, OS command execution, SSRF/outbound fetch, open redirects.\n10) Concurrency/resource exhaustion (unbounded goroutines/queues, missing timeouts/contexts).\n11) Use of `unsafe` / `cgo` / `reflect` in security-sensitive paths.\n12) Debug/diagnostic endpoints (pprof/expvar/metrics) exposure.\n13) Cryptography usage (randomness, password hashing).\n\n--------------------------------------------------------------------\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\nExamples include:\n- `*http.Request` fields: `r.URL.Path`, `r.URL.RawQuery`, `r.Form`, `r.PostForm`, headers, cookies, `r.Body`\n- Path parameters from routers (including values extracted from URL paths)\n- JSON/XML/YAML bodies, multipart form parts, uploaded files\n- Any data from external systems (webhooks, third-party APIs, message queues)\n- Any persisted user content (DB rows) that originated from users\n- Configuration values that might be attacker-influenced in some deployments (headers set by upstream proxies, environment variables in multi-tenant systems)\n\n### 2.2 State-changing request\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook send), or initiate privileged actions.\n\n### 2.3 Required audit finding format\nFor each issue found, output:\n\n- Rule ID:\n- Severity: Critical / High / Medium / Low\n- Location: file path + function/handler name + line(s)\n- Evidence: the exact code/config snippet\n- Impact: what could go wrong, who can exploit it\n- Fix: safe change (prefer minimal diff)\n- Mitigation: defense-in-depth if immediate fix is hard\n- False positive notes: what to verify if uncertain (edge configs, proxy behavior, auth assumptions)\n\n--------------------------------------------------------------------\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common Go misconfigurations.\n\n### 3.1 Toolchain, patching, and dependency hygiene (MUST)\n- MUST run a supported Go major version and keep to the latest patch releases.\n- MUST treat Go standard library patch releases as security-relevant (many security fixes land in stdlib components like `net/http`, `crypto/*`, parsing packages).\n- MUST use Go modules with committed `go.mod` and `go.sum`.\n- MUST NOT disable module authenticity mechanisms for public modules (checksum DB) unless you have a controlled, documented replacement.\n- MUST run `govulncheck` (source scan and/or binary scan) in CI and address findings.\n\n### 3.2 HTTP server baseline (MUST for network-facing services)\nIf the program serves HTTP (directly or via a framework built on `net/http`):\n- MUST configure an `http.Server` with explicit timeouts and header limits.\n- MUST set request body size limits (global and per-route as needed).\n- MUST avoid exposing diagnostic endpoints (pprof/expvar) publicly.\n- SHOULD set a consistent set of security headers (or verify they are set at the edge).\n- MUST set cookie security attributes for any cookies you issue.\n- SHOULD implement rate limiting and abuse controls for auth and expensive endpoints.\n\nIllustrative baseline skeleton (adjust to your project):\n- Create a dedicated mux (avoid implicit global defaults unless intentionally managed).\n- Wrap handlers with: panic-safe error handling, request ID, logging, auth, and limits.\n\n--------------------------------------------------------------------\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### GO-DEPLOY-001: Keep the Go toolchain and standard library updated (security releases)\nSeverity: Medium\n\nNOTE: Upgrading dependencies and the core Go version can break projects in unexpected ways. Focus on only security-critical dependencies and if noticed, let the user know rather than upgrading automatically.\n\nRequired:\n- MUST run a supported Go major release and apply patch releases promptly.\n- SHOULD treat patch releases as security-relevant, even if your application code didn’t change.\n\nInsecure patterns:\n- Production builds pinned to old Go versions without a patching process.\n- Docker images like `golang:1.xx` or custom base images that are not updated regularly.\n- CI pipelines that intentionally suppress Go updates.\n\nDetection hints:\n- Inspect CI (`.github/workflows`, `gitlab-ci.yml`, etc.) for `go-version:` or toolchain setup.\n- Inspect Dockerfiles for `FROM golang:` tags.\n- Inspect `go.mod` `go` directive and any toolchain pinning.\n\nFix:\n- Upgrade to the latest patch of a supported Go version.\n- Add an automated check (CI) that fails when Go is below an approved minimum.\n\nNotes:\n- Go publishes regular minor releases that frequently include security fixes across standard library packages.\n\n---\n\n### GO-SUPPLY-001: Go module authenticity MUST NOT be disabled for public dependencies\nSeverity: High\n\nRequired:\n- MUST keep module checksum verification enabled for public modules.\n- SHOULD commit `go.sum` and treat changes as security-sensitive.\n- MUST NOT use insecure module fetching settings for public modules.\n- MAY configure private module behavior using `GOPRIVATE`/`GONOSUMDB` for private repos, but must do so narrowly and intentionally.\n\nInsecure patterns:\n- `GOSUMDB=off` in CI or production build environments for public modules.\n- `GONOSUMDB=*` or overly broad patterns that effectively disable verification.\n- `GOINSECURE=*` or broad `GOINSECURE` patterns for public modules.\n- `GOPROXY=direct` everywhere without a clear policy.\n\nDetection hints:\n- Search build configs for `GOSUMDB`, `GONOSUMDB`, `GOINSECURE`, `GOPROXY`, `GOPRIVATE`.\n- Look for documentation/scripts that recommend disabling checksum DB “to make builds work”.\n\nFix:\n- Restore defaults for public module verification.\n- For private modules:\n  - Set `GOPRIVATE=your.private.domain/*`\n  - Configure an internal proxy or direct fetching, and restrict `GONOSUMDB` to private patterns only.\n\nNotes:\n- Disabling checksum verification removes an important integrity layer against targeted or compromised upstream delivery.\n\n---\n\n### GO-CONFIG-001: Secrets must be externalized and never logged or committed\nSeverity: High (Critical if credentials are committed)\n\nRequired:\n- MUST load secrets from environment variables, secret managers, or secure config files with restricted permissions.\n- MUST NOT hard-code secrets in Go source, test fixtures that may reach production, or build args.\n- MUST NOT log secrets or full credential-bearing connection strings.\n- SHOULD fail closed in production if required secrets are missing.\n\nInsecure patterns:\n- String constants containing tokens/keys/passwords.\n- `.env` files or config files with secrets committed to repo.\n- Logging `os.Environ()`, dumping full configs, or printing DSNs.\n\nDetection hints:\n- Search for suspicious literals (`API_KEY`, `SECRET`, `PASSWORD`, `Authorization:`).\n- Inspect config loaders and logging statements.\n- Inspect CI logs or debug print paths.\n\nFix:\n- Move secrets to a secret store / environment variables.\n- Redact sensitive fields in logs.\n- Add secret scanning to CI and pre-commit.\n\n---\n\n### GO-HTTP-001: HTTP servers MUST set timeouts and MaxHeaderBytes\nSeverity: High (DoS risk)\n\nRequired:\n- MUST set: `ReadHeaderTimeout`, and SHOULD set `ReadTimeout`, `WriteTimeout`, `IdleTimeout` as appropriate for the service.\n- MUST set `MaxHeaderBytes` to a justified limit for your application.\n- MUST NOT rely on default zero-values for timeouts in production for internet-facing servers.\n\nInsecure patterns:\n- `http.ListenAndServe(\":8080\", handler)` with a default `http.Server` (no explicit timeouts).\n- `&http.Server{}` with timeouts left at zero.\n- Missing `MaxHeaderBytes`.\n\nDetection hints:\n- Search for `http.ListenAndServe(`, `ListenAndServeTLS(`, `Server{` and inspect configured fields.\n- Check for reverse proxies; even with a proxy, app-level timeouts still matter.\n\nFix:\n- Use `http.Server{ReadHeaderTimeout: ..., ReadTimeout: ..., WriteTimeout: ..., IdleTimeout: ..., MaxHeaderBytes: ...}`.\n- Calibrate timeouts per endpoint type (streaming vs JSON APIs).\n\nNotes:\n- Net/http documents that these timeouts exist and that zero/negative values mean “no timeout”; production services should choose explicit values.\n\n---\n\n### GO-HTTP-002: Request body and multipart parsing MUST be size-bounded\nSeverity: Medium (DoS risk; can be High for upload-heavy apps)\n\nRequired:\n- MUST enforce a global maximum request body size for endpoints that accept bodies.\n- MUST enforce strict multipart upload limits and avoid unbounded form parsing.\n- SHOULD enforce per-route limits when some endpoints legitimately need larger bodies.\n- SHOULD set upstream (proxy) limits as defense-in-depth.\n\nInsecure patterns:\n- Reading `r.Body` with `io.ReadAll(r.Body)` without a size cap.\n- Calling `r.ParseMultipartForm(...)` with overly large limits (or forgetting size controls).\n- Accepting file uploads with no limits on file size, number of parts, or total body size.\n\nDetection hints:\n- Search for `io.ReadAll(r.Body)`, `json.NewDecoder(r.Body)`, `ParseMultipartForm`, `FormFile`, `multipart`.\n- Look for missing `http.MaxBytesReader` or equivalent per-handler limiting.\n- Look for “upload” endpoints and check limits.\n\nFix:\n- Wrap request bodies with `http.MaxBytesReader(w, r.Body, maxBytes)` before parsing.\n- For multipart, set conservative limits and validate file sizes/part counts explicitly.\n- Set proxy limits (e.g., at ingress) in addition to app limits.\n\nNotes:\n- There are known vulnerability classes and advisories related to excessive resource consumption in multipart/form parsing; treat unbounded parsing as a security issue.\n\n---\n\n### GO-DEPLOY-002: Diagnostic endpoints (pprof/expvar/metrics) MUST NOT be publicly exposed\nSeverity: High\n\nNOTE: This only applies to production configurations. These endpoints are often used for debug or dev endpoints. If found, confirm that it would be reachable from the actual production deployment.\n\nRequired:\n- MUST NOT expose `net/http/pprof` handlers on a public internet-facing listener without strong access controls.\n- SHOULD run diagnostics on a separate, internal-only listener (loopback/VPC-only) and require auth.\n- MUST review what diagnostic endpoints reveal (stack traces, memory, command lines, environment, internal URLs).\n\nInsecure patterns:\n- Side-effect import `import _ \"net/http/pprof\"` in a server binary with a public mux.\n- `/debug/pprof/*` reachable without auth.\n- `/debug/vars` (expvar) reachable without auth.\n\nDetection hints:\n- Search for `net/http/pprof` imports (including blank imports).\n- Search for route prefixes `/debug/pprof`, `/debug/vars`.\n- Check whether `http.DefaultServeMux` is used and whether any debug handlers register globally.\n\nFix:\n- Remove diagnostics from production builds, or bind them to an internal-only listener.\n- Add strong authentication/authorization (and ideally network-level restrictions).\n\nNotes:\n- pprof is typically imported for its side effect of registering HTTP handlers under `/debug/pprof/`.\n\n---\n\n### GO-HTTP-003: Reverse proxy and forwarded header trust MUST be explicit\nSeverity: High (auth, URL generation, logging/auditing correctness)\n\nRequired:\n- If behind a reverse proxy, MUST define which proxy is trusted and how client IP/scheme/host are derived.\n- MUST NOT trust `X-Forwarded-For`, `X-Forwarded-Proto`, `Forwarded`, or similar headers from the open internet.\n- MUST ensure “secure cookie” logic, redirects, and absolute URL generation do not rely on spoofable headers.\n\nInsecure patterns:\n- Using `r.Header.Get(\"X-Forwarded-For\")` as the client IP without validating the proxy boundary.\n- Deriving “is HTTPS” from `X-Forwarded-Proto` without confirming it came from a trusted proxy.\n- Using forwarded `Host` values for password reset links without allowlisting.\n\nDetection hints:\n- Search for `X-Forwarded-For`, `X-Forwarded-Proto`, `Forwarded`, `Real-IP`, and any custom “client IP” helpers.\n- Inspect ingress/proxy configs; if not visible, mark as “verify at edge”.\n\nFix:\n- Enforce proxy trust at the edge and in app:\n  - Accept forwarded headers only from known proxy IP ranges.\n  - Prefer platform-provided mechanisms where available.\n- If generating external links, use a configured allowlisted canonical origin (not the request’s Host header).\n\n---\n\n### GO-HTTP-004: Security headers SHOULD be set (in app or at the edge)\nSeverity: Medium\n\nRequired (typical web app serving browsers):\n- SHOULD set:\n  - `Content-Security-Policy` (CSP) appropriate to the app. NOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n  - `X-Content-Type-Options: nosniff`\n  - Clickjacking protection (`X-Frame-Options` and/or CSP `frame-ancestors`)\n  - `Referrer-Policy` and `Permissions-Policy` where appropriate\n- MUST ensure cookies have secure attributes (see GO-HTTP-005).\n\nNOTE:\n- These headers may be set via reverse proxy/CDN; if not visible in app code, report as “verify at edge”.\n\nInsecure patterns:\n- No security headers anywhere (app or edge) for a browser-facing app.\n- CSP missing for apps rendering untrusted content.\n\nDetection hints:\n- Search for middleware setting headers: `w.Header().Set(\"Content-Security-Policy\", ...)`, etc.\n- Search for reverse proxy config that sets headers.\n\nFix:\n- Add centralized header middleware in Go, or configure at the edge.\n- Keep CSP realistic; avoid `unsafe-inline` where possible.\n\n---\n\n### GO-HTTP-005: Cookies MUST use secure attributes in production\nSeverity: Medium\n\nRequired (production, HTTPS):\n- MUST set `Secure` on cookies that carry auth/session state. IMPORTANT NOTE: Only set `Secure` in production environment when TLS is configured. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n- MUST set `HttpOnly` on auth/session cookies.\n- SHOULD set `SameSite=Lax` by default (or `Strict` if compatible), and only use `None` when necessary (and only with `Secure`).\n- SHOULD set bounded lifetimes (`Max-Age`/`Expires`) appropriate to the app.\n\nInsecure patterns:\n- Setting auth/session cookies without `Secure` in HTTPS deployments.\n- Cookies without `HttpOnly` for session identifiers.\n- `SameSite=None` for cookie-authenticated apps without a strong CSRF strategy.\n\nDetection hints:\n- Search for `http.SetCookie`, `&http.Cookie{`, `Set-Cookie`.\n- Inspect cookie flags in auth/session code.\n\nFix:\n- Set the correct fields on `http.Cookie` and centralize cookie creation.\n\nNotes:\n- SameSite is defense-in-depth and does not replace CSRF protections for cookie-auth apps.\n\n---\n\n### GO-HTTP-006: Cookie-authenticated state-changing endpoints MUST be CSRF-protected\nSeverity: High\n\n- IMPORTANT NOTE: If cookies are not used for auth (e.g., pure bearer token in Authorization header with no ambient cookies), CSRF is not a risk for those endpoints.\n\nRequired:\n- MUST protect all state-changing endpoints (POST/PUT/PATCH/DELETE) that rely on cookies for authentication.\n- SHOULD use a well-tested CSRF library/middleware rather than rolling your own.\n- MAY use additional defenses (Origin/Referer checks, Fetch Metadata, SameSite cookies), but tokens remain the primary defense for cookie-authenticated apps.\nIf tokens are impractical, or for small applications:\n* MUST at a minimum require a custom header to be set and set the session cookie SESSION_COOKIE_SAMESITE=lax, as this is the strongest method besides requiring a form token, and may be much easier to implement.\n\n\nInsecure patterns:\n- Cookie-authenticated JSON endpoints that mutate state with no CSRF checks.\n- Using GET for state-changing actions.\n\nDetection hints:\n- Enumerate all non-GET routes and identify auth mechanism.\n- Look for CSRF middleware usage; if absent, treat as suspicious in browser-facing apps.\n\nFix:\n- Add CSRF middleware and ensure it covers all state-changing routes.\n- If the service is an API intended for non-browser clients, avoid cookie auth; use Authorization headers.\n\n---\n\n### GO-HTTP-007: CORS must be explicit and least-privilege\nSeverity: Medium (High if misconfigured with credentials)\n\nRequired:\n- If CORS is not needed, MUST keep it disabled.\n- If CORS is needed:\n  - MUST allowlist trusted origins (do not reflect arbitrary origins)\n  - MUST be careful with credentialed requests; do not combine broad origins with cookies\n  - SHOULD restrict allowed methods/headers\n\nInsecure patterns:\n- `Access-Control-Allow-Origin: *` paired with cookies (`Access-Control-Allow-Credentials: true`).\n- Reflecting `Origin` without validation.\n\nDetection hints:\n- Search for `Access-Control-Allow-` header setting.\n- Search for CORS middleware configuration.\n\nFix:\n- Implement strict origin allowlists and minimal methods/headers.\n- Ensure cookie-auth endpoints are not exposed cross-origin unless required.\n\n---\n\n### GO-XSS-001: Use html/template and avoid bypassing auto-escaping with untrusted data\nSeverity: High\n\nRequired:\n- MUST use `html/template` for HTML rendering (not `text/template`).\n- MUST NOT convert untrusted data into “trusted” template types (`template.HTML`, `template.JS`, `template.URL`, etc.).\n- SHOULD keep templates static and controlled by developers; treat dynamic templates as high risk.\n- MUST NOT serve user-uploaded HTML/JS as active content unless explicitly intended and safely sandboxed.\n\nInsecure patterns:\n- `text/template` used to generate HTML.\n- Using `template.HTML(userInput)` or similar typed wrappers.\n- Directly writing unescaped user content into HTML responses.\n\nDetection hints:\n- Search for `text/template`, `template.New(...).Parse(...)`, and typed wrappers like `template.HTML(`.\n- Inspect handlers that return HTML with string concatenation.\n\nFix:\n- Use `html/template` and pass untrusted data as data, not markup.\n- If you must allow limited HTML, use a vetted HTML sanitizer and still be careful with attributes/URLs.\n\n---\n\n### GO-SSTI-001: Never parse/execute templates from untrusted input (SSTI)\nSeverity: Critical\n\nRequired:\n- MUST NOT call `template.Parse` / `template.ParseFiles` / `template.New(...).Parse(...)` on template text influenced by untrusted input.\n- MUST treat “user-defined templates” as a special high-risk design:\n  - MUST use heavy sandboxing and strict allowlists\n  - MUST isolate execution (process/container boundary) if truly required\n\nInsecure patterns:\n- `tmpl := template.Must(template.New(\"x\").Parse(r.FormValue(\"tmpl\")))`\n- Reading templates from uploads / DB entries and executing them in the same trust domain as server code.\n\nDetection hints:\n- Search for `.Parse(` and trace the origin of the template string.\n- Look for “custom email templates”, “user theming templates”, etc.\n\nFix:\n- Replace with safe substitution mechanisms (no code execution).\n- If templates must be user-controlled, isolate and sandbox aggressively.\n\n---\n\n### GO-PATH-001: Prevent path traversal and unsafe file serving\nSeverity: High\n\nRequired:\n- MUST NOT pass user-controlled paths to `os.Open`, `os.ReadFile`, `http.ServeFile`, or `http.FileServer` without strict validation and base-dir enforcement.\n- MUST treat `..`, absolute paths, and OS-specific path tricks as hostile input.\n- SHOULD store user uploads outside any static web root; serve through controlled handlers.\n- MUST avoid directory listing for sensitive file trees.\n\nInsecure patterns:\n- `http.ServeFile(w, r, r.URL.Query().Get(\"path\"))`\n- `os.Open(filepath.Join(baseDir, userPath))` without checking that the result stays under `baseDir`\n- `http.FileServer(http.Dir(\".\"))` serving the project root or user-writable directories\n\nDetection hints:\n- Search for `ServeFile(`, `FileServer(`, `http.Dir(`, `os.Open(`, `ReadFile(`, `filepath.Join(`.\n- Trace whether path components come from request/DB.\n\nFix:\n- Use an allowlist of file identifiers (e.g., database IDs) mapped to server-side paths.\n- Enforce base directory containment after cleaning and joining.\n- Serve active formats as downloads (`Content-Disposition: attachment`) unless explicitly intended.\n\n---\n\n### GO-UPLOAD-001: File uploads must be validated, stored safely, and served safely\nSeverity: High\n\nRequired:\n- MUST enforce upload size limits (app + edge).\n- MUST validate file type using allowlists and content checks (not only extensions).\n- MUST store uploads outside executable/static roots when possible.\n- SHOULD generate server-side filenames (random IDs) and avoid trusting original names.\n- MUST serve potentially active formats safely (download attachment) unless explicitly intended.\n\nInsecure patterns:\n- Accepting arbitrary file types and serving them back inline.\n- Using user-supplied filename as storage path.\n- Missing size/type validation.\n\nDetection hints:\n- Search for `multipart`, `FormFile`, `ParseMultipartForm`, `io.Copy` to disk.\n- Check where files are stored and how they are served.\n\nFix:\n- Implement allowlist validation + safe storage + safe serving.\n- Add scanning/quarantine workflows where applicable.\n\n---\n\n### GO-INJECT-001: Prevent SQL injection (parameterized queries / ORM)\nSeverity: High\n\nRequired:\n- MUST use parameterized queries or an ORM that parameterizes under the hood.\n- MUST NOT build SQL by string concatenation / `fmt.Sprintf` / string interpolation with untrusted input.\n\nInsecure patterns:\n- `fmt.Sprintf(\"SELECT ... WHERE id=%s\", r.URL.Query().Get(\"id\"))`\n- `query := \"UPDATE users SET role='\" + role + \"' WHERE id=\" + id`\n\nDetection hints:\n- Grep for `SELECT`, `INSERT`, `UPDATE`, `DELETE` and check how query strings are built.\n- Trace untrusted data into `db.Query`, `db.Exec`, `QueryRow`, etc.\n\nFix:\n- Replace with placeholders (`?`, `$1`, etc.) and pass parameters separately.\n- Validate and type-check IDs before use.\n\n---\n\n### GO-INJECT-002: Prevent OS command injection; avoid shelling out with untrusted input\nSeverity: Critical to High (depends on exposure)\n\nRequired:\n- MUST avoid executing external commands with attacker-controlled strings.\n- If subprocess is necessary:\n  - MUST use `exec.CommandContext` with an argument list (not `sh -c`).\n  - MUST NOT pass untrusted input to a shell (`bash -c`, `sh -c`, PowerShell).\n  - SHOULD use strict allowlists for any variable component (subcommand, flags, filenames).\n- MUST assume CLI tools may interpret attacker-controlled args as flags or special values.\n\nInsecure patterns:\n- `exec.Command(\"sh\", \"-c\", userString)`\n- `exec.Command(\"bash\", \"-c\", fmt.Sprintf(\"tool %s\", user))`\n- Calling the shell to get glob expansion for user-supplied globs.\n\nDetection hints:\n- Search for `os/exec`, `exec.Command(`, `CommandContext(`, `\"sh\"`, `\"bash\"`, `\"-c\"`.\n- Trace untrusted input into command name/args.\n\nFix:\n- Use library APIs instead of subprocesses.\n- Hardcode command and allowlist/validate args.\n- If a shell is unavoidable, escape robustly and treat as high risk (prefer avoiding).\n\nNotes:\n- The Go `os/exec` package intentionally does invoke a shell; introducing `sh -c` reintroduces shell injection hazards.\n\n---\n\n### GO-SSRF-001: Prevent SSRF in outbound HTTP requests\nSeverity: Medium (High in cloud/LAN environments)\n\n- Note: For small stand alone projects this is less important. It is most important when deploying into an LAN or with other services listening on the same server.\n\nRequired:\n- MUST treat outbound requests to user-provided URLs as high risk.\n- SHOULD allowlist hosts/domains for any user-influenced URL fetch.\n- SHOULD block access to localhost/private IP ranges/link-local addresses and cloud metadata endpoints.\n- MUST restrict schemes to `http`/`https` (no `file:`, `gopher:`, etc.).\n- MUST set client timeouts and restrict redirects.\n\nInsecure patterns:\n- `http.Get(r.URL.Query().Get(\"url\"))`\n- “URL preview” / “webhook test” endpoints that fetch arbitrary URLs.\n\nDetection hints:\n- Search for `http.Get`, `client.Do`, and URL values derived from requests/DB.\n- Identify features that fetch remote resources.\n\nFix:\n- Parse URLs strictly; enforce scheme and allowlisted hostnames.\n- Resolve DNS and enforce IP-range restrictions (with care for DNS rebinding).\n- Set timeouts, disable redirects unless needed, and cap response sizes.\n\n---\n\n### GO-HTTPCLIENT-001: Outbound HTTP clients MUST set timeouts and close bodies\nSeverity: High (DoS and resource exhaustion)\n\nRequired:\n- MUST set an overall timeout on `http.Client` usage (or equivalent per-request deadlines via context + transport timeouts).\n- MUST ensure `resp.Body.Close()` is called for all successful requests (typically `defer resp.Body.Close()` immediately after error check).\n- SHOULD limit response body reads (do not `io.ReadAll` unbounded responses).\n- SHOULD restrict redirects for security-sensitive fetches (SSRF, auth flows).\n\nInsecure patterns:\n- Using `http.DefaultClient` / `http.Get` for user-influenced destinations with no timeout policy.\n- Missing `defer resp.Body.Close()` leading to resource leaks.\n- `io.ReadAll(resp.Body)` with no limit.\n\nDetection hints:\n- Search for `http.Get(`, `http.Post(`, `client := &http.Client{}` without `Timeout`, `client.Do(` and missing closes.\n- Search for `io.ReadAll(resp.Body)`.\n\nFix:\n- Use a configured client with timeouts.\n- Always close response bodies.\n- Use bounded readers (`io.LimitReader`) for large/untrusted responses.\n\nNotes:\n- The net/http package exposes `DefaultClient` as a zero-valued `http.Client`, which can easily lead to “no timeout” behavior unless configured.\n\n---\n\n### GO-REDIRECT-001: Prevent open redirects\nSeverity: Medium (can be High with auth flows)\n\nRequired:\n- MUST validate redirect targets derived from untrusted input (`next`, `redirect`, `return_to`).\n- SHOULD prefer only same-site relative paths.\n- SHOULD fall back to a safe default on validation failure.\n\nInsecure patterns:\n- `http.Redirect(w, r, r.URL.Query().Get(\"next\"), http.StatusFound)` with no validation.\n\nDetection hints:\n- Search for `http.Redirect(` and check origin of the location.\n\nFix:\n- Allowlist internal paths or known domains.\n- Reject absolute URLs unless explicitly needed and allowlisted.\n\n---\n\n### GO-CRYPTO-001: Cryptographic randomness MUST come from crypto/rand\nSeverity: High (Critical if used for auth/session tokens or keys)\n\nRequired:\n- MUST use `crypto/rand` for:\n  - session IDs, password reset tokens, API keys, CSRF tokens, nonces\n  - encryption keys, signing keys, salts when required\n- MUST NOT use `math/rand` for any security-sensitive value.\n- SHOULD use built-in helpers that produce appropriately strong tokens when available.\n\nInsecure patterns:\n- `math/rand.Seed(time.Now().UnixNano())` followed by token generation for auth or sessions.\n- Using UUIDv4-like constructs built from `math/rand`.\n\nDetection hints:\n- Search for `math/rand`, `rand.Seed`, `rand.Intn` in code that touches auth/session/token flows.\n- Search for custom token generators.\n\nFix:\n- Switch to `crypto/rand` (`rand.Reader`, `rand.Read`, or secure token helpers).\n- Ensure sufficient entropy and use URL-safe encoding.\n\nNotes:\n- The crypto/rand package provides secure randomness APIs and token generation helpers.\n\n---\n\n### GO-AUTH-001: Password storage MUST use adaptive hashing (bcrypt/argon2id) and safe comparisons\nSeverity: High\n\nRequired:\n- MUST hash passwords using an adaptive password hashing function (bcrypt or argon2id).\n- MUST NOT store plaintext passwords or reversible encryption of passwords.\n- MUST compare secrets in constant time when relevant (tokens, MACs, API keys) to reduce timing leaks.\n- SHOULD ensure password policies do not exceed algorithm constraints (e.g., bcrypt has input length limits; handle long passphrases appropriately).\n\nInsecure patterns:\n- `sha256(password)` stored as password hash.\n- Plaintext password storage.\n- Comparing secrets with `==` in timing-sensitive contexts.\n\nDetection hints:\n- Search for `sha1`, `sha256`, `md5` used on passwords.\n- Search for `bcrypt`/`argon2` usage; if absent, suspect.\n- Search for `==` comparisons on tokens/API keys.\n\nFix:\n- Use `bcrypt.GenerateFromPassword` / `CompareHashAndPassword` or argon2id with recommended parameters.\n- Use constant-time compare helpers when comparing MACs/tokens.\n\nNotes:\n- Go provides bcrypt in `golang.org/x/crypto/bcrypt`, and constant-time comparisons in `crypto/subtle`.\n\n---\n\n### GO-CONC-001: Data races and concurrency hazards MUST be treated as security-relevant\nSeverity: Medium to High (depends on what races affect)\n\nRequired:\n- MUST run tests with the race detector (`go test -race`) in CI for security-sensitive services.\n- MUST fix detected races; do not suppress without deep justification.\n- SHOULD treat shared mutable state in handlers as high risk; enforce synchronization or avoid shared mutability.\n\nInsecure patterns:\n- Global maps/slices mutated from multiple goroutines without a mutex.\n- Caches or auth/session state stored in globals without concurrency protection.\n- Racy access to authorization state (can lead to bypasses or inconsistent enforcement).\n\nDetection hints:\n- Search for `var someMap = map[...]...` used in handlers.\n- Look for missing `sync.Mutex`, `sync.Map`, channels, or other synchronization.\n- Ensure CI includes `-race` and that it runs relevant tests.\n\nFix:\n- Add proper synchronization or redesign to avoid shared mutable state.\n- Add race tests and run them continuously.\n\nNotes:\n- The Go race detector only finds races that occur in executed code paths; improve test coverage and run realistic workloads with `-race` where feasible.\n\n---\n\n### GO-UNSAFE-001: Use of unsafe/cgo MUST be minimized and audited like memory-unsafe code\nSeverity: High (Critical in high-risk code paths)\n\nRequired:\n- SHOULD avoid importing `unsafe` in application code unless absolutely necessary.\n- If `unsafe` is used, MUST treat it as “manual memory safety” requiring careful review and test coverage.\n- If `cgo` is used, MUST treat the C/C++ boundary as memory-unsafe; apply secure coding practices on the C side and isolate where possible.\n\nInsecure patterns:\n- Widespread `unsafe.Pointer` casts in parsing, serialization, auth, or network code.\n- `cgo` used for parsing or security boundaries without sandboxing.\n\nDetection hints:\n- Search for `import \"unsafe\"`, `unsafe.Pointer`, `// #cgo`, `import \"C\"`.\n- Prioritize review where unsafe touches untrusted input.\n\nFix:\n- Replace unsafe/cgo usage with safe standard library alternatives where possible.\n- Isolate unsafe code in small, well-tested modules with fuzz/race tests.\n\nNotes:\n- The unsafe package explicitly provides operations that step around Go’s type safety guarantees.\n\n--------------------------------------------------------------------\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\nToolchain & dependencies:\n- `FROM golang:` (Dockerfiles), `go-version:` (CI), `toolchain go` (go.mod), pinned old versions\n- `GOSUMDB=off`, `GOINSECURE`, `GONOSUMDB`, `GOPROXY=direct`\n- `replace` directives in `go.mod` to forks/paths\n- `govulncheck` missing in CI\n\nHTTP server hardening:\n- `http.ListenAndServe(`, `ListenAndServeTLS(`, `&http.Server{` with missing timeouts\n- `ReadHeaderTimeout: 0`, `ReadTimeout: 0`, `WriteTimeout: 0`, `IdleTimeout: 0`, missing `MaxHeaderBytes`\n\nBody parsing / DoS:\n- `io.ReadAll(r.Body)`, `json.NewDecoder(r.Body)` without size cap\n- `ParseMultipartForm`, `FormFile`, `multipart.NewReader` without explicit limits\n- Missing `http.MaxBytesReader`\n\nDebug exposure:\n- `import _ \"net/http/pprof\"`\n- `/debug/pprof`, `/debug/vars`\n\nTemplates / XSS / SSTI:\n- `text/template` used for HTML output\n- `template.HTML(`, `template.JS(`, `template.URL(` with user-controlled data\n- `.Parse(` on user-controlled strings\n\nFiles:\n- `http.ServeFile(` with user path\n- `http.FileServer(http.Dir(` pointing at repo root or uploads\n- `os.Open(filepath.Join(base, user))` without containment checks\n\nInjection:\n- SQL building with `fmt.Sprintf`, string concatenation near `db.Query/Exec`\n- `exec.Command(\"sh\",\"-c\", ...)`, `exec.Command(\"bash\",\"-c\", ...)`\n\nSSRF / outbound HTTP:\n- `http.Get(userURL)`, `client.Do(req)` where URL comes from request/DB\n- Missing client timeout, missing `resp.Body.Close()`, unbounded `io.ReadAll(resp.Body)`\n\nCrypto:\n- `math/rand` in token/session generation\n- `InsecureSkipVerify: true`\n- Password hashing with `sha256`/`md5` instead of bcrypt/argon2\n\nConcurrency:\n- Shared maps/slices mutated from handlers without locks\n- CI lacking `go test -race`\n\nAlways try to confirm:\n- data origin (untrusted vs trusted)\n- sink type (template/SQL/subprocess/files/http)\n- protective controls present (limits, validation, allowlists, middleware, network controls)\n\n--------------------------------------------------------------------\n\n## 6) Sources (accessed 2026-01-28)\n\nPrimary Go documentation:\n- Go Security Policy — https://go.dev/doc/security/policy\n- Go Release History (security fixes in patch releases) — https://go.dev/doc/devel/release\n- Go 1.25 Release Notes — https://go.dev/doc/go1.25\n- net/http (server timeouts, MaxHeaderBytes, DefaultClient) — https://pkg.go.dev/net/http\n- html/template (auto-escaping and trusted-template assumptions) — https://pkg.go.dev/html/template\n- crypto/tls (MinVersion defaults, InsecureSkipVerify warnings) — https://pkg.go.dev/crypto/tls\n- crypto/rand (secure randomness, token helpers) — https://pkg.go.dev/crypto/rand\n- crypto/subtle (constant-time comparisons) — https://pkg.go.dev/crypto/subtle\n- os/exec (no shell by default; command execution guidance) — https://pkg.go.dev/os/exec\n- unsafe (bypasses type safety) — https://go.dev/src/unsafe/unsafe.go\n- net/http/pprof (debug endpoints) — https://pkg.go.dev/net/http/pprof\n- cmd/go (module authentication via go.sum/checksum DB; env vars like GOINSECURE) — https://pkg.go.dev/cmd/go\n- Module Mirror and Checksum Database Launched (Go blog) — https://go.dev/blog/module-mirror-launch\n- govulncheck documentation — https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck\n- Go Race Detector documentation — https://go.dev/doc/articles/race_detector\n- bcrypt (password hashing) — https://pkg.go.dev/golang.org/x/crypto/bcrypt\n- Go vulnerability entry example (multipart resource consumption) — https://pkg.go.dev/vuln/GO-2023-1569\n\nOWASP Cheat Sheet Series (general web security):\n- Session Management — https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html\n- CSRF Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html\n- SSRF Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html\n- XSS Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html\n- HTTP Security Response Headers — https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html\n\n<!-- File: core/skills/builtin/security-best-practices/references/javascript-express-web-server-security.md (Tokens: ~10932 | Category: anthropic-skill) -->\n# Express (Node.js) Web Security Spec (Express 5.x / 4.19.2+, Node.js LTS)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new Express apps and routes.\n2. **Security review / vulnerability hunting** in existing Express code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session secrets, cookies, tokens).\n* MUST NOT “fix” security by disabling protections (e.g., weakening cookie flags, disabling CSRF defenses for cookie-authenticated apps, enabling permissive CORS, trusting proxy headers from the open internet, turning on debugging/stack traces in production, disabling TLS without a replacement).\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, middleware/config values, and runtime assumptions that justify the claim.\n* MUST treat uncertainty honestly: if a protection might exist in infrastructure (reverse proxy, gateway, WAF, CDN), report it as “not visible in app code; verify at runtime/config.”\n* MUST prefer vetted libraries and platform controls over “roll your own” crypto/auth/session/CSRF. Express explicitly expects the application to validate/handle user input correctly; it does not do this automatically. ([Express][1])\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new Express code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default APIs and proven libraries over custom security code.\n* MUST avoid introducing new risky sinks (shell execution, dynamic code evaluation, unsafe redirects, serving user files as HTML, template rendering from untrusted strings, unsafe filesystem paths, SSRF URL fetch endpoints, etc.).\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in an Express repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. Entrypoints (server/app bootstrap), deployment manifests, Dockerfiles, process manager config, CI/CD.\n2. Express settings + middleware stack order (helmet, parsers, auth, sessions, CSRF, CORS).\n3. Proxy trust (`trust proxy`) and IP/protocol/host handling. ([Express][2])\n4. Auth flows, sessions, cookies, password reset links, redirect handling. ([Express][1])\n5. State-changing routes + CSRF protections (cookie-authenticated apps). ([OWASP Cheat Sheet Series][3])\n6. Template rendering and XSS defenses (HTML generation, CSP, `res.locals`). ([OWASP Cheat Sheet Series][4])\n7. File handling (uploads + downloads + static files) and path traversal. ([Express][5])\n8. Injection classes (SQL, NoSQL, command execution, unsafe deserialization). ([OWASP Cheat Sheet Series][6])\n9. Outbound requests (SSRF) and webhook/callback delivery. ([OWASP Cheat Sheet Series][7])\n10. Rate limiting / brute-force defenses / abuse controls. ([Express][1])\n11. Dependency hygiene / lockfiles / npm audit / vulnerable Express versions. ([Express][1])\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nIn Express, common untrusted inputs include:\n\n* `req.params` (route parameters)\n* `req.query` (query string parameters; can be strings/arrays/objects depending on parsing) ([OWASP Cheat Sheet Series][8])\n* `req.body` from `express.json()`, `express.urlencoded()`, `express.text()`, `express.raw()` ([Express][5])\n* `req.headers` / `req.get(...)`\n* `req.cookies` / `req.signedCookies` (if cookie parsing middleware is used)\n* Upload metadata and filenames (e.g., multer `file.originalname`, `file.mimetype`)\n* Any data from external systems (webhooks, third-party APIs, message queues)\n* Any persisted user content (DB rows) that originated from users\n\nSpecial proxy note:\n\n* If `trust proxy` is enabled, values like `req.ip`, `req.hostname`, and `req.protocol` may be derived from `X-Forwarded-*` headers which **can be attacker-controlled** if your proxy chain is not correctly overwriting/removing them. ([Express][2])\n\n### 2.2 State-changing request\n\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook send), or initiate privileged actions.\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + function/route/middleware name + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common Express misconfigurations.\n\nMinimum baseline targets:\n\n* `helmet()` is used and configured (especially CSP where applicable), and fingerprinting is reduced (disable `x-powered-by`). ([Express][1])\n* A custom 404 handler and a custom error handler exist, and production does not leak internal stack traces. ([Express][1])\n* Cookie/session usage is deliberate:\n\n  * Not using default session cookie names\n  * Cookies use secure attributes (`Secure`, `HttpOnly`, `SameSite`) as appropriate\n  * Cookie-backed sessions never store secrets (they are readable by the client)\n  * Server-side sessions never use MemoryStore in production. ([Express][1])\n* Request body parsing has explicit limits (`express.json({ limit })`, `express.urlencoded({ limit, parameterLimit, depth })`). ([Express][5])\n* `trust proxy` is configured explicitly to match your proxy topology; not blindly `true`. ([Express][2])\n* Login/auth endpoints have brute-force protection and rate limiting. ([Express][1])\n* Dependencies are regularly audited/updated (`npm audit` + advisory response). ([Express][1])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### EXPRESS-INPUT-001: Treat all user input as untrusted and validate it\n\nSeverity: High\n\nRequired:\n\n* MUST validate and normalize untrusted inputs before using them in security-sensitive logic or dangerous sinks (DB queries, redirects, filesystem, HTML output, shell commands). Ensure the untrusted inputs are type checked and structure checked before using or passing forward.\n* SHOULD apply allowlists (known-good) rather than blocklists when feasible.\n* MUST reject or safely handle unexpected types/shapes in `req.query`, `req.params`, and `req.body`.\n\nInsecure patterns:\n\n* Passing `req.query`, `req.params`, `req.body` directly into database/query builders, redirects, filesystem paths, or templates.\n* Assuming `req.query.foo` is always a string (it can be an array/object depending on parsing). ([OWASP Cheat Sheet Series][8])\n\nDetection hints:\n\n* Identify “untrusted-to-sink” flows: request → sink (`res.redirect`, SQL execution, `sendFile`, `child_process`, template render, outbound fetch).\n* Search for direct usage of `req.query.*`, `req.body.*`, `req.params.*` in sensitive calls.\n\nFix:\n\n* Add schema validation (e.g., zod/joi/express-validator) at route boundaries.\n* Normalize types (e.g., force IDs to integers; reject arrays when scalar expected).\n\nNotes:\n\n* Express production security guidance explicitly says input validation/handling is the application’s responsibility. ([Express][1])\n\n---\n\n### EXPRESS-REDIRECT-001: Prevent open redirects; validate redirect targets\n\nSeverity: Medium\n\nRequired:\n\n* MUST validate redirect destinations derived from untrusted input (`next`, `return_to`, `url`).\n* SHOULD allowlist only same-site relative paths (preferred) or a strict allowlist of domains.\n* MUST fall back to a safe default when validation fails.\n\nInsecure patterns:\n\n* `res.redirect(req.query.next)` with no validation.\n* `res.redirect(req.body.url)` or `res.location(...)` using untrusted URLs.\n\nDetection hints:\n\n* Search for `res.redirect(` and `res.location(` and trace the source of the target.\n* Look for query params named `next`, `redirect`, `return`, `url`.\n\nFix:\n\n* Only allow relative paths (starting with `/`) and disallow `//`, backslashes, and encoded variants.\n* If cross-domain redirects are required, allowlist exact hosts and enforce `https`.\n\nNotes:\n\n* Express documentation calls out open redirects as dangerous user input and shows validating the host before redirecting. ([Express][1])\n* Keep Express updated: Express has had an open-redirect-related CVE affecting some versions, and upgrades are part of the mitigation posture. ([NVD][9])\n\n---\n\n### EXPRESS-HEADERS-001: Use Helmet (or equivalent) to set essential security headers\n\nSeverity: Medium\n\nRequired:\n\n* SHOULD use `helmet()` to set common security headers.\n* SHOULD configure CSP realistically (avoid `unsafe-inline` where possible) for pages that render user-influenced content.\n* SHOULD set `X-Content-Type-Options: nosniff`, clickjacking defenses (`X-Frame-Options` or CSP `frame-ancestors`), and appropriate referrer policy.\n\nNOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n\nInsecure patterns:\n\n* No security headers set in app code and no evidence they are set at the edge.\n* CSP missing on apps that display user content.\n* Misconfigured framing headers that unintentionally allow clickjacking.\n\nDetection hints:\n\n* Search for `helmet(` usage; check if CSP is configured or disabled.\n* Search for `res.setHeader(` / `res.set(` for security header setting.\n* If not visible in app code, check nginx/CDN config; otherwise flag “verify at edge.”\n\nFix:\n\n* Add `helmet()` early in middleware order and configure:\n\n  * CSP (`contentSecurityPolicy`)\n  * Frame protections (`frameguard` or CSP `frame-ancestors`)\n  * `X-Content-Type-Options` (`noSniff`)\n\nNotes:\n\n* Express production security best practices recommend Helmet and list headers Helmet sets by default. ([Express][1])\n* OWASP HTTP Headers guidance is a useful reference when tuning policies. ([OWASP Cheat Sheet Series][10])\n\n---\n\n### EXPRESS-FINGERPRINT-001: Reduce fingerprinting by disabling `x-powered-by` and customizing error/404 responses\n\nSeverity: Low (defense-in-depth)\n\nRequired:\n\n* SHOULD disable `X-Powered-By` using `app.disable('x-powered-by')`.\n* SHOULD provide a custom 404 handler and a custom error handler to avoid distinct default responses and to control information leakage.\n\nInsecure patterns:\n\n* Default `X-Powered-By: Express` header left enabled.\n* Default Express 404/error responses in production with identifiable formatting and/or stack traces.\n\nDetection hints:\n\n* Search for `app.disable('x-powered-by')`.\n* Check middleware tail for a custom 404 (`app.use((req,res)=>...)`) and a custom error handler (`app.use((err,req,res,next)=>...)`).\n* Check if `NODE_ENV` is correctly set for production behavior (see EXPRESS-ERROR-001). ([Express][11])\n\nFix:\n\n* Add:\n\n  * `app.disable('x-powered-by')`\n  * A custom 404 handler\n  * A custom error handler that logs server-side and returns generic messages client-side\n\nNotes:\n\n* Express docs explicitly recommend disabling `x-powered-by` and adding your own not-found and error handlers. ([Express][1])\n\n---\n\n### EXPRESS-COOKIE-001: Cookies must use secure attributes and minimal scope\n\nSeverity: Medium\n\nRequired:\n\n* MUST set cookie flags appropriately for any authentication/session cookie:\n\n  * `Secure` when HTTPS (production) IMPORTANT NOTE: Only set `Secure` in production environment if TLS is configured. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n  * `HttpOnly` for auth/session cookies\n  * `SameSite` set deliberately (`Lax` is a common baseline; `Strict` if compatible; `None` only with `Secure` and a justified cross-site need)\n* SHOULD avoid setting `domain` broadly (avoid “all subdomains” unless required).\n* SHOULD set bounded expiry appropriate to risk and UX.\n\nInsecure patterns:\n\n* Session/auth cookies without `HttpOnly`.\n* Cookies without `Secure` in production HTTPS.\n* `SameSite=None` + cookie-authenticated state-changing endpoints without CSRF protections.\n\nDetection hints:\n\n* Search for `res.cookie(`, `Set-Cookie`, `cookie: { ... }`, `express-session`, `cookie-session`.\n* Verify cookie flags in session middleware configuration.\n\nFix:\n\n* Set these attributes centrally in session/cookie middleware configuration.\n\nNotes:\n\n* Express production security guidance lists cookie security options (`secure`, `httpOnly`, etc.). ([Express][1])\n* `res.cookie()` ultimately sets `Set-Cookie` with options; defaults follow RFC 6265 behavior when options are omitted. ([Express][5])\n* OWASP session management guidance is relevant for choosing flags and lifetimes. ([OWASP Cheat Sheet Series][12])\n\n---\n\n### EXPRESS-SESS-001: Do not use the default session cookie name; avoid session fingerprinting\n\nSeverity: Low (defense-in-depth)\n\nRequired:\n\n* SHOULD override the default session cookie name (e.g., do not keep `connect.sid` when using `express-session`).\n* SHOULD use a generic name (e.g., `sessionId`) unless you have a compatibility reason.\n\nInsecure patterns:\n\n* `express-session` used with no `name:` configured (default cookie name).\n* Multiple apps on the same domain sharing a cookie name accidentally.\n\nDetection hints:\n\n* Search for `express-session` config blocks; check for `name:`.\n\nFix:\n\n* Set `name: 'sessionId'` (or similar) in `express-session` options.\n\nNotes:\n\n* Express docs explicitly recommend not using the default session cookie name to reduce fingerprinting. ([Express][1])\n\n---\n\n### EXPRESS-SESS-002: Session storage and lifecycle must be production-safe\n\nSeverity: High\n\nRequired:\n\n* MUST NOT use `MemoryStore` in production (it is not designed for production use).\n* MUST store session secrets outside source control and rotate them safely.\n* SHOULD regenerate sessions on login / privilege changes to reduce session fixation risk.\n* MUST NOT store sensitive secrets in client-readable cookie sessions.\n\nInsecure patterns:\n\n* `app.use(session({ store: new MemoryStore(), ... }))` or missing store (defaults to MemoryStore).\n* Hard-coded for example: `secret: 'keyboard cat'` / `secret: 's3Cur3'` in repo.\n* Using `cookie-session` to store access tokens, refresh tokens, or PII.\n\nDetection hints:\n\n* Search for `express-session` and look for `MemoryStore` usage or missing `store`.\n* Search for `secret:` in session config and check if it’s hard-coded.\n* Look for `req.session = ...` patterns and whether sensitive data is stored.\n\nFix:\n\n* Use a production session store (Redis, database-backed, etc.).\n* Load secrets from environment/secret manager.\n* On login: `req.session.regenerate(...)` or equivalent flow with safe privilege re-binding.\n\nNotes:\n\n* `express-session` explicitly warns that `MemoryStore` is not designed for production. ([Express][1])\n* `express-session` documents rotating secrets and session regeneration to guard against fixation. ([Express][1])\n* Express notes that cookie-backed sessions serialize data into the cookie and that cookie data is visible to the client; keep it small and non-secret. ([Express][1])\n\n---\n\n### EXPRESS-CSRF-001: Cookie-authenticated state-changing requests MUST be CSRF-protected\n\nSeverity: High\n\n- IMPORTANT NOTE: If cookies are not being used for auth (ie auth is via Authentication header or other passed token), then there is no CSRF risk.\n\nRequired:\n\n* MUST protect all state-changing endpoints (POST/PUT/PATCH/DELETE) that rely on cookies for authentication.\n* SHOULD use a well-understood CSRF mitigation (token-based is the typical baseline).\n* MAY add defense-in-depth: Origin/Referer validation, Fetch Metadata enforcement, SameSite cookies, custom header requirements for XHR/fetch—**but do not treat these as a full replacement** unless explicitly designed and justified.\n* MUST use at a minimum require a custom HTTP header if form based CRSF tokens are not practical, as this is the second strongest method.\n\nIMPORTANT NOTE:\n\n* If authentication is done via `Authorization: Bearer ...` headers (and not cookies), classic browser CSRF is typically not applicable;\n\nInsecure patterns:\n\n* Cookie-authenticated endpoints that change state with no CSRF protection.\n* Using GET for state-changing actions (amplifies CSRF risk).\n* “CSRF protection” that only checks a user-controlled field.\n\nDetection hints:\n\n* Enumerate routes with methods other than GET/HEAD and identify whether cookies gate auth.\n* Look for presence/absence of CSRF middleware and token checks.\n* Check JSON APIs too, not only HTML forms.\n\nFix:\n\n* Implement CSRF tokens for cookie-authenticated flows.\n* Add Origin/Referer checks where feasible, and ensure SameSite is set appropriately.\n\nNotes:\n\n* OWASP CSRF guidance and OWASP Node.js guidance both recommend anti-CSRF tokens as a standard control for web apps. ([OWASP Cheat Sheet Series][3])\n\n---\n\n### EXPRESS-CORS-001: CORS must be explicit and least-privilege\n\nSeverity: Medium (High if misconfigured with credentials)\n\nRequired:\n\n* If CORS is not needed, MUST keep it disabled.\n* If CORS is needed:\n\n  * MUST allowlist trusted origins (do not reflect arbitrary `Origin` without validation).\n  * MUST NOT combine broad origins with credentialed cookies (`Access-Control-Allow-Credentials: true`).\n  * SHOULD restrict methods, headers, and exposed headers to what’s required.\n\nInsecure patterns:\n\n* `Access-Control-Allow-Origin: *` with `Access-Control-Allow-Credentials: true`.\n* Reflecting `Origin` for all requests without allowlist validation.\n* Applying permissive CORS middleware globally when only a subset needs cross-origin access.\n\nDetection hints:\n\n* Search for `cors(`, `Access-Control-Allow-Origin`, `Access-Control-Allow-Credentials`.\n* Inspect whether cookies are used for auth on endpoints exposed cross-origin.\n\nFix:\n\n* Implement strict origin allowlist and ensure credentialed requests only for intended origins.\n* Consider splitting CORS config per route group rather than global.\n\nNotes:\n\n* OWASP HTTP header guidance covers security implications of response headers, including those that affect browser behavior; use it as a reference when reviewing header posture. ([OWASP Cheat Sheet Series][10])\n\n---\n\n### EXPRESS-PROXY-001: Reverse proxy trust (`trust proxy`) must be configured correctly\n\nSeverity: Medium (High if using IP based authentication)\n\nRequired:\n\n* If behind a reverse proxy/LB, MUST configure `app.set('trust proxy', ...)` to match the real proxy chain.\n* MUST NOT blindly set `trust proxy = true` unless you fully control the proxy behavior and header rewriting.\n* MUST ensure the last trusted proxy overwrites/removes `X-Forwarded-For`, `X-Forwarded-Host`, and `X-Forwarded-Proto` so clients cannot spoof them.\n\nInsecure patterns:\n\n* `app.set('trust proxy', true)` in an app directly exposed to the internet or behind unknown proxies.\n* Using `req.ip`, `req.protocol`, `req.hostname` for security decisions without correct proxy trust configuration.\n* Rate limiting keyed by `req.ip` with spoofable forwarded headers.\n\nDetection hints:\n\n* Search for `app.set('trust proxy'`.\n* Check infra docs (nginx/LB) for header rewriting behavior.\n* Identify any security logic using `req.ip`, `req.ips`, `req.protocol`, `req.hostname`.\n\nFix:\n\n* Set `trust proxy` to a hop count, explicit IP/subnet list, or a custom function matching your network.\n* Ensure proxies overwrite forwarded headers.\n\nNotes:\n\n* Express explicitly warns that when `trust proxy` is `true`, the client IP is derived from `X-Forwarded-For`, and if proxies don’t overwrite forwarded headers, the client can provide any value. It also describes that enabling trust proxy impacts `req.hostname` and `req.protocol` derived from forwarded headers. ([Express][2])\n\n---\n\n### EXPRESS-BODY-001: Request body size and parsing limits MUST be set appropriately\n\nSeverity: Low\n\nRequired:\n\n* SHOULD set explicit body size limits for:\n\n  * `express.json({ limit })`\n  * `express.urlencoded({ limit, parameterLimit, depth })`\n* SHOULD only enable the parsers you need; do not parse large bodies by default for all routes.\n* SHOULD enforce additional limits at the reverse proxy / gateway level.\n\nInsecure patterns:\n\n* No explicit body limits (accepting arbitrarily large JSON/urlencoded).\n* Global parsers applied to all routes when only some need bodies.\n* `parameterLimit` very high without justification (DoS potential).\n\nDetection hints:\n\n* Search for `express.json(` and confirm `limit` is set (or consciously accepted).\n* Search for `express.urlencoded(` and inspect `limit`, `parameterLimit`, and `depth`.\n* Review upload/webhook endpoints for special parsing needs.\n\nFix:\n\n* Configure parsers with conservative defaults and override per route group when needed.\n\nNotes:\n\n* Express documents `express.json` options (including `limit`, defaulting to 100kb) and explicitly notes `req.body` is untrusted and should be validated. ([Express][5])\n* Express documents `express.urlencoded` options including `limit`, `parameterLimit`, and `depth`. ([Express][5])\n* OWASP Node.js guidance also recommends setting request size limits. ([OWASP Cheat Sheet Series][8])\n\n---\n\n### EXPRESS-INPUT-002: Prevent HTTP Parameter Pollution and type confusion in `req.query`\n\nSeverity: Medium\n\nRequired:\n\n* MUST treat `req.query` values as potentially multi-valued (array/object), depending on query parsing.\n* SHOULD reject ambiguous multi-valued parameters for security-sensitive fields (e.g., `role`, `isAdmin`, `redirect`, `amount`, `userId`).\n* SHOULD consider explicit parsing or dedicated middleware if parameter pollution is a concern.\n\nInsecure patterns:\n\n* `if (req.query.admin) { ... }` without type checks (arrays/objects may coerce truthy).\n* Passing `req.query` directly into ORM/NoSQL query objects.\n\nDetection hints:\n\n* Search for security-sensitive comparisons on `req.query.*` without type enforcement.\n* Look for code that assumes query params are strings.\n\nFix:\n\n* Validate shape: enforce string-only for certain params and reject arrays/objects.\n* Normalize query parsing settings (simple vs extended) where applicable and documented.\n\nNotes:\n\n* OWASP Node.js cheat sheet explicitly highlights that Express query parsing can produce strings, arrays, or objects and recommends preventing HTTP Parameter Pollution. ([OWASP Cheat Sheet Series][8])\n\n---\n\n### EXPRESS-XSS-001: Prevent reflected/stored XSS in HTML responses and templating\n\nSeverity: High\n\nRequired:\n\n* MUST escape untrusted content in HTML output (templates should auto-escape by default; do not bypass).\n* MUST NOT inject untrusted strings into HTML without escaping/sanitization.\n* SHOULD set CSP (via Helmet) for apps rendering user-controlled content.\n* SHOULD keep `res.locals` free of user-controlled input intended for templates unless it is validated/escaped.\n\nInsecure patterns:\n\n* `res.send(\"<div>\" + req.query.q + \"</div>\")`\n* Passing untrusted HTML through “safe” template flags/filters.\n* Writing untrusted strings into `res.locals` and then rendering without escaping.\n\nDetection hints:\n\n* Search for `res.send(` with strings containing user input.\n* Search for template “safe” flags (engine-specific) and trace data origin.\n* Search for assignments to `res.locals` and whether they might contain untrusted data.\n\nFix:\n\n* Use a template engine with autoescaping; pass only validated data.\n* For rich text that must contain HTML, use a trusted sanitizer and an allowlist policy.\n* Add CSP with realistic directives.\n\nNotes:\n\n* Express API docs explicitly warn that `res.locals` “should not contain user-controlled input” and is often used to expose things like CSRF tokens to templates. ([Express][5])\n* OWASP XSS prevention guidance provides standard output-encoding and policy recommendations. ([OWASP Cheat Sheet Series][4])\n* Helmet can mitigate some XSS classes via headers such as CSP. ([Express][1])\n\n---\n\n### EXPRESS-TEMPLATE-001: Never render untrusted templates or template paths (SSTI / LFI risk)\n\nSeverity: Critical (if you can prove template strings/paths are user/attacker-controlled)\n\nRequired:\n\n* MUST NOT render templates whose contents or template path/name is influenced by untrusted input.\n* MUST NOT load templates from user-controlled filesystem locations.\n* SHOULD treat “email template editors”, “theme engines”, and “CMS-like template storage” as high-risk designs requiring sandboxing and isolation.\n\nInsecure patterns:\n\n* `res.render(req.query.view, data)` where `view` is not allowlisted.\n* Rendering a template from a string that includes user input (engine-specific).\n* Loading templates from uploads directories.\n\nDetection hints:\n\n* Search for `res.render(` where the first argument is derived from request/DB without allowlist.\n* Search for template compilation APIs (engine-specific) fed by user content.\n\nFix:\n\n* Use allowlisted template names and a fixed templates directory.\n* If user-defined templates are required, implement strict sandboxing and isolate execution.\n\nNotes:\n\n* Express’s template system depends on the chosen engine; assume unsafe if user input influences template selection or source.\n\n---\n\n### EXPRESS-FILES-001: Prevent path traversal and unsafe file serving (sendFile/download)\n\nSeverity: High\n\nRequired:\n\n* MUST NOT pass user-controlled filesystem paths directly to `res.sendFile()` / `res.download()` / filesystem APIs.\n* SHOULD use `res.sendFile` with a fixed `root` and strict options (e.g., deny dotfiles) when serving user-selected files from a directory.\n* MUST enforce authorization checks before serving user-specific files.\n\nInsecure patterns:\n\n* `res.sendFile(req.query.path)` or `res.download(req.params.file)` with no root restriction.\n* File-serving routes that accept `..` segments, encoded traversal, or absolute paths.\n\nDetection hints:\n\n* Search for `res.sendFile(` and trace the `path` argument origin.\n* Search for `res.download(` and trace the `path` argument origin.\n* Look for `fs.readFile`/`createReadStream` on paths derived from requests.\n\nFix:\n\n* Use an identifier-to-path mapping stored server-side (DB), not raw paths from clients.\n* Use `root: <trusted_base_dir>` and `dotfiles: 'deny'` where appropriate; validate the filename component strictly.\n\nNotes:\n\n* Express’s `res.sendFile` docs show using a `root` option and `dotfiles: 'deny'` as part of a safe serving configuration. ([Express][5])\n* `res.download` transfers the file as an attachment, but you still must control/validate the underlying `path`. ([Express][5])\n\n---\n\n### EXPRESS-STATIC-001: Harden `express.static` / serve-static and never serve untrusted uploads as active content\n\nSeverity: Medium (if serving untrusted user files if there are not robust limits tot eh file extensions)\n\nRequired:\n\n* MUST NOT serve user uploads from a public static directory as active content (especially HTML/JS/SVG) unless explicitly intended and sandboxed. If sure that the content is inactive (png, jpg, other images etc) then it may be safe. It may be good to validate image file extensions are allow-listed before serving them.\n* SHOULD configure static serving to:\n\n  * deny/ignore dotfiles\n  * avoid unintended directory indexes if not needed\n  * apply appropriate cache controls for immutable assets\n\nInsecure patterns:\n\n* `app.use(express.static('uploads'))` where users can upload arbitrary files.\n* Serving uploaded HTML or SVG inline from the same origin as the app.\n\nDetection hints:\n\n* Search for `express.static(` and identify served directories.\n* Compare served directories with upload storage locations.\n* Check for `dotfiles` and `index` options in static middleware.\n\nFix:\n\n* Store uploads outside any static web root and serve via controlled routes that set safe `Content-Type` and `Content-Disposition: attachment` when appropriate.\n* Configure `express.static(root, { dotfiles: 'deny'|'ignore', index: false (if desired) })`.\n\nNotes:\n\n* Express documents `express.static` options, including `dotfiles` behavior and `index`. ([Express][5])\n\n---\n\n### EXPRESS-UPLOAD-001: File uploads must be validated, stored safely, and served safely\n\nSeverity: Low - Medium\n\nRequired:\n\n* SHOULD enforce upload size limits (app + edge).\n* MUST validate file type using allowlists and content checks (not only filename extension).\n* MUST store uploads outside executable/static roots when possible.\n* SHOULD generate server-side filenames (random IDs); do not trust original names.\n* MUST serve potentially active formats safely (download attachment) unless explicitly intended.\n\nInsecure patterns:\n\n* Accepting arbitrary file types and serving them back inline.\n* Using `file.originalname` as the storage path.\n* Missing size/type validation.\n\nDetection hints:\n\n* Look for multer/busboy/formidable usage and check for `limits`.\n* Check where uploaded files are written and how they are served.\n* Check whether uploads end up under `public/` or any `express.static` root.\n\nFix:\n\n* Implement allowlist validation + safe storage + safe serving, per OWASP upload guidance.\n\nNotes:\n\n* OWASP File Upload guidance covers allowlists, content validation, storage, and safe serving patterns. ([OWASP Cheat Sheet Series][13])\n\n---\n\n### EXPRESS-INJECT-001: Prevent SQL injection (use parameterized queries / ORM)\n\nSeverity: High\n\nRequired:\n\n* MUST use parameterized queries or an ORM/query builder that parameterizes under the hood.\n* MUST NOT build SQL via string concatenation/template literals with untrusted input.\n\nInsecure patterns:\n\n* ``db.query(`SELECT * FROM users WHERE id = ${req.query.id}`)``\n* `\"SELECT ... WHERE name = '\" + req.body.name + \"'\"`\n\nDetection hints:\n\n* Grep for `SELECT`, `INSERT`, `UPDATE`, `DELETE` strings in JS/TS.\n* Trace untrusted input into `.query(...)`, `.execute(...)`, or raw SQL APIs.\n\nFix:\n\n* Replace with parameterized queries (placeholders) or ORM query APIs.\n* Validate types (e.g., integer IDs) before querying.\n\nNotes:\n\n* OWASP SQL injection prevention guidance strongly favors parameterized queries. ([OWASP Cheat Sheet Series][6])\n\n---\n\n### EXPRESS-INJECT-002: Prevent NoSQL injection / operator injection (Mongo-style)\n\nSeverity: High (app-dependent)\n\nRequired:\n\n* MUST validate types and schemas for any query object built from untrusted input.\n* MUST prevent operator injection (e.g., `$ne`, `$gt`, `$where`) if user input is merged into query objects.\n* SHOULD consider defensive libraries/middleware when appropriate.\n\nInsecure patterns:\n\n* `collection.find(req.body)` where the body is attacker-controlled.\n* Merging `req.query`/`req.body` into Mongo queries without schema validation.\n\nDetection hints:\n\n* Search for `find(`, `findOne(`, `aggregate(` calls where argument is request-derived.\n* Check for patterns like `{ ...req.query }` or `Object.assign(query, req.body)`.\n\nFix:\n\n* Use schema validation at boundary; explicitly construct query objects from validated fields only.\n\nNotes:\n\n* OWASP Node.js cheat sheet discusses input validation and mentions Node ecosystem modules commonly used for sanitization in NoSQL contexts. ([OWASP Cheat Sheet Series][8])\n\n---\n\n### EXPRESS-CMD-001: Prevent OS command injection (child_process)\n\nSeverity: Critical to High (depends on exposure), please prove it is user/attacker controlled\n\nRequired:\n\n* MUST avoid executing shell commands with untrusted input.\n* If subprocess is necessary:\n\n  * MUST avoid `exec()` / `execSync()` with attacker-influenced strings\n  * MUST NOT use `shell: true` with attacker-influenced data\n  * SHOULD use `spawn()` with an argument array and strict allowlists. Ensure the executable is hardcoded or allow-listed, do not use a user supplied command name.\n  * SHOULD place user-controlled values after `--` when supported by the subcommand to avoid flag injection\n\nInsecure patterns:\n\n* `exec(req.query.cmd)`\n* `exec(`convert ${userPath} ...`)`\n* `spawn('sh', ['-c', userString])`\n* `spawn(userString, ['foo'])`\n\nDetection hints:\n\n* Search for `child_process`, `exec(`, `execSync(`, `spawn(`, `fork(`.\n* Trace request/DB data into command construction.\n\nFix:\n\n* If possible, write the functionality in javascript or use a library instead of subprocess.\n* If unavoidable, hard-code command and strictly allowlist parameters.\n\nNotes:\n\n* OWASP OS command injection defense guidance covers avoid-shell and allowlist patterns. ([OWASP Cheat Sheet Series][14])\n\n---\n\n### EXPRESS-SSRF-001: Prevent server-side request forgery (SSRF) in outbound HTTP\n\nSeverity: Medium (High in cloud/LAN deployments)\n\nNOTE: This is mostly only applicable to apps which will be deployed in a cloud/LAN setup or have other http services on the same box. Sometimes the feature requires this functionality unavoidably (webhooks).\n\nRequired:\n\n* MUST treat outbound requests to user-provided URLs as high risk if there are other reachable private http endpoints.\n* SHOULD validate and restrict destinations (allowlist hosts/domains) for any user-influenced URL fetch.\n* SHOULD block access to:\n\n  * localhost / private IP ranges / link-local\n  * cloud metadata endpoints\n* MUST allow only `http`/`https` for URL fetch features (to avoid schemas such as `file:`,`javascript:`)\n* SHOULD set timeouts and restrict redirects.\n\nInsecure patterns:\n\n* `fetch(req.query.url)`\n* “URL preview” / “import from URL” endpoints that accept arbitrary URLs.\n\nDetection hints:\n\n* Search for `fetch(`, `axios(`, `got(`, `request(`, `node-fetch` usage where URL originates from users/DB.\n* Review webhook testers, previewers, image fetchers.\n\nFix:\n\n* Enforce scheme allowlist, host allowlist, DNS/IP resolution checks, timeouts, and redirect policy.\n* Consider network egress controls at infrastructure level.\n\nNotes:\n\n* OWASP SSRF prevention guidance provides standard controls and common pitfalls. ([OWASP Cheat Sheet Series][7])\n\n---\n\n### EXPRESS-ERROR-001: Error handling MUST not leak sensitive details in production\n\nSeverity: Low\n\nRequired:\n\n* SHOULD define a centralized error handler (`app.use((err, req, res, next) => ...)`) at the end of middleware.\n* MUST avoid returning stack traces, internal error messages, or secrets to clients in production.\n* SHOULD log errors server-side with appropriate redaction.\n* SHOULD ensure the app runs with production settings so default behavior doesn’t leak details.\n* MUST avoid logging or returning sensitive information such as secrets, env vars, sessions, cookies in error messages in production.\n\nInsecure patterns:\n\n* Returning `err.stack` to clients.\n* Using dev-only error middleware in production.\n* `NODE_ENV` left as development, causing verbose error responses.\n\nDetection hints:\n\n* Verify there is a final error-handling middleware.\n* Search for `res.status(500).send(err)` or similar.\n* Check production environment variables and startup scripts.\n\nFix:\n\n* Add a production-safe error handler that returns generic messages and logs details internally.\n* Ensure environment is configured for production behavior.\n\nNotes:\n\n* Express production security guidance recommends custom error handling. ([Express][1])\n* Express error handling docs describe the default error handler behavior and how production mode affects what is exposed. ([Express][11])\n\n---\n\n### EXPRESS-AUTH-001: Prevent brute-force attacks against authorization endpoints\n\nSeverity: Medium\n\nNOTE: This is highly application specific and while it is good to bring to the attention of the user, it is hard to fix without additional complex configurations. Prefer to inform the user and if they request you to help implement a solution, help walk them through possible solutions.\n\nRequired:\n\n* SHOULD protect login/auth endpoints against brute forcing.\n* SHOULD rate-limit by:\n\n  1. consecutive failed attempts per username+IP\n  2. failed attempts per IP over a time window\n\nInsecure patterns:\n\n* Unlimited login attempts.\n\nDetection hints:\n\n* Identify all auth endpoints and check for rate limiting/throttling.\n* Search for `rate-limiter-flexible`, `express-rate-limit`, or gateway policies.\n\nFix:\n\n* Implement rate-limiting/throttling (app or edge). Express docs point to `rate-limiter-flexible` as a tool for this approach. ([Express][1])\n\nNotes:\n\n* OWASP Node.js cheat sheet also recommends precautions against brute forcing. ([OWASP Cheat Sheet Series][8])\n\n---\n\n### EXPRESS-DEPS-001: Dependency and patch hygiene (Express + Node + critical middleware)\n\nSeverity: Medium / Low\n\nNOTE: `npm audit` often returns a large number of insignificant \"vulnerabilities\" which do not actually matter. You should only focus on Express or other extremely critical packages, ignoring ones listed in dev tools, bundlers, etc.\n\nDo not upgrade packages without concent from the user. This may break existing code in unexpected ways. Instead, inform them of the outdated packages.\n\nRequired:\n\n* MUST keep Express on a maintained version line (avoid EOL major versions).\n* MAY use `npm audit` in CI and during maintenance work.\n* SHOULD pin dependencies via lockfiles and review major updates carefully.\n\nInsecure patterns:\n\n* Running EOL Express versions (e.g., very old major lines).\n* Ignoring `npm audit` findings without triage.\n* Unpinned dependency ranges that auto-upgrade into insecure versions.\n\nDetection hints:\n\n* Check `package.json` and lockfiles for `express` version and other critical middleware versions.\n* Inspect CI pipelines for `npm audit`/SCA steps.\n\nFix:\n\n* Upgrade to latest stable Express and apply patches.\n* Add automated dependency scanning and upgrade process.\n\nNotes:\n\n* Express production security guidance emphasizes that dependency vulnerabilities can compromise the app, and recommends `npm audit`. ([Express][1])\n* Track security issues affecting Express versions (including known open-redirect-related CVEs). ([NVD][9])\n\n---\n\n### EXPRESS-DOS-001: Configure DoS protections (timeouts, limits, reverse proxy)\n\nSeverity: Low\n\nNOTE: It may be hard to tell from the provided application context if the application runs behind a reverse proxy. You can inform the user or recommend one, but do not attempt to configure one without them initiating it. This is highly deployment dependant.\n\nRequired:\n\n* SHOULD use a reverse proxy to provide caching, load balancing, and filtering controls when feasible.\n* MAY configure server/proxy timeouts and connection limits to reduce exposure to Slowloris and similar DoS patterns.\n* MUST ensure server/socket errors are handled so malformed connections do not crash the process. (Express should handle exceptions, but there are edgecases)\n\nInsecure patterns:\n\n* No reverse proxy in front of a public Node server, with defaults everywhere.\n* Missing error handlers on server/socket objects.\n* Extremely permissive timeouts and unlimited body sizes.\n\nDetection hints:\n\n* Inspect server creation (`http.createServer`, `https.createServer`) and whether timeouts are set.\n* Check proxy/gateway config for timeouts and max body size.\n\nFix:\n\n* Explain how to configure reverse proxy and timeouts, set request size limits\n* add robust error handling middleware\n\nNotes:\n\n* Node’s security guidance for HTTP DoS discusses using reverse proxies and correctly configuring server timeouts. ([Node.js][15])\n\n---\n\n### EXPRESS-NODE-INSPECT-001: Do not expose the Node inspector in production\n\nSeverity: Critical\n\nNOTE: Ensure that this detection is actually in the production path, and not just being used for local debugging.\n\nRequired:\n\n* MUST NOT run Node with `--inspect` (especially bound to non-loopback) in production.\n* MUST ensure `NODE_OPTIONS` or startup scripts do not enable inspector in prod.\n* SHOULD firewall/debug locally only.\n\nInsecure patterns:\n\n* `node --inspect=0.0.0.0:9229 app.js` in production.\n* Container/PM2/systemd configs enabling inspector.\n\nDetection hints:\n\n* Search for `--inspect` in Dockerfiles, Procfiles, systemd units, PM2 configs, npm scripts.\n* Check `NODE_OPTIONS`.\n\nFix:\n\n* Remove inspector flags from production start commands; restrict to local dev.\n\nNotes:\n\n* Node security guidance discusses inspector exposure risks (e.g., DNS rebinding) and recommends not running inspector in production. ([Node.js][15])\n\n---\n\n### EXPRESS-NODE-HTTP-001: Do not enable insecure HTTP parsing in production\n\nSeverity: High\n\nNOTE: Ensure that this detection is actually in the production path, and not just being used for local dev.\n\nRequired:\n\n* MUST NOT use Node’s `insecureHTTPParser` in production.\n* MAY suggest configuring front-end proxies to normalize ambiguous requests to reduce request smuggling risk.\n\nInsecure patterns:\n\n* Creating an HTTP server with `{ insecureHTTPParser: true }`.\n\nDetection hints:\n\n* Search for `insecureHTTPParser` in server creation code.\n\nFix:\n\n* Remove insecure parsing; rely on spec-compliant parsing and normalize at the edge.\n\nNotes:\n\n* Node security guidance explicitly recommends not using `insecureHTTPParser`. ([Node.js][15])\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning an Express repo, these patterns are high-signal:\n\n* TLS / transport:\n\n  * `app.listen(80` without reverse proxy mention; missing `helmet`; cookies missing `secure` ([Express][1]) (NOTE this only applies to web facing applications, internal apps likely won't have TLS)\n* Proxy trust:\n\n  * `app.set('trust proxy', true)`; logic using `req.ip`/`req.protocol`/`req.hostname` ([Express][2])\n* Security headers / fingerprinting:\n\n  * missing `helmet(`; missing `app.disable('x-powered-by')` ([Express][1])\n* Cookies / sessions:\n\n  * `express-session` with missing `store` (MemoryStore risk), hard-coded `secret:`, missing `cookie: { secure/httpOnly/sameSite }` ([Express][1])\n  * `cookie-session` storing large objects or secrets ([Express][1])\n* Body parsing limits:\n\n  * `express.json()` or `express.urlencoded()` without `limit`/`parameterLimit`/`depth` ([Express][5])\n* CSRF:\n\n  * POST/PUT/PATCH/DELETE routes using cookie auth with no CSRF tokens/origin checks ([OWASP Cheat Sheet Series][3])\n* Open redirects:\n\n  * `res.redirect(req.query.next)` or similar ([Express][1])\n* XSS / HTML output:\n\n  * `res.send(` building HTML with user input; template “safe” flags; untrusted values in `res.locals` ([Express][5])\n* File handling:\n\n  * `res.sendFile(` / `res.download(` where path originates from request; `express.static('uploads')` ([Express][5])\n* Injection:\n\n  * SQL strings + template literals into DB calls ([OWASP Cheat Sheet Series][6])\n  * `child_process.exec` / `execSync` / `shell: true` ([OWASP Cheat Sheet Series][14])\n* SSRF:\n\n  * outbound `fetch/axios/got` to user-provided URLs ([OWASP Cheat Sheet Series][7])\n* Brute force / abuse:\n\n  * auth endpoints lacking throttling; no rate limiting middleware ([Express][1])\n* Supply chain:\n\n  * outdated Express versions; no lockfiles; no `npm audit` workflow ([Express][1])\n* Node runtime hazards:\n\n  * `--inspect` in production scripts; `insecureHTTPParser` usage ([Node.js][15])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (HTML/template, SQL/NoSQL, subprocess, filesystem, redirect, outbound HTTP)\n* protective controls present (validation, allowlists, middleware, proxy config, header policies)\n* whether protections are at the edge vs in app code\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary Express documentation:\n\n* Express: Production Best Practices — Security: `https://expressjs.com/en/advanced/best-practice-security.html` ([Express][1])\n* Express: Behind Proxies (`trust proxy`): `https://expressjs.com/en/guide/behind-proxies.html` ([Express][2])\n* Express 5.x API Reference (parsers, static, sendFile, redirect, cookies): `https://expressjs.com/en/5x/api.html` ([Express][5])\n* Express: Error Handling: `https://expressjs.com/en/guide/error-handling.html` ([Express][11])\n\nSession middleware documentation:\n\n* express-session docs (cookie flags, secret rotation, fixation mitigation, MemoryStore warning): `https://expressjs.com/en/resources/middleware/session.html` ([Express][1])\n\nNode.js and npm official references:\n\n* Node.js — Security Best Practices (DoS, proxy guidance, inspector risks, request smuggling notes): `https://nodejs.org/en/learn/getting-started/security-best-practices` ([Node.js][15])\n* npm Docs — `npm audit`: `https://docs.npmjs.com/cli/v9/commands/npm-audit/` ([npm Docs][16])\n\nOWASP Cheat Sheet Series:\n\n* Session Management: `https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][12])\n* CSRF Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][3])\n* XSS Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][4])\n* Input Validation: `https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][17])\n* SQL Injection Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][6])\n* OS Command Injection Defense: `https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][14])\n* SSRF Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][7])\n* File Upload: `https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][13])\n* Unvalidated Redirects: `https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][18])\n* HTTP Headers: `https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][10])\n\nVersioning / advisories:\n\n* Express package version (npm): `https://www.npmjs.com/package/express`\n* Express open redirect advisory (CVE): `https://nvd.nist.gov/vuln/detail/CVE-2024-29041` ([NVD][9])\n\n[1]: https://expressjs.com/en/advanced/best-practice-security.html \"Security Best Practices for Express in Production\"\n[2]: https://expressjs.com/en/guide/behind-proxies.html \"Express behind proxies\"\n[3]: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html \"Cross-Site Request Forgery Prevention - OWASP Cheat Sheet Series\"\n[4]: https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html \"Cross Site Scripting Prevention - OWASP Cheat Sheet Series\"\n[5]: https://expressjs.com/en/5x/api.html \"Express 5.x - API Reference\"\n[6]: https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html \"SQL Injection Prevention - OWASP Cheat Sheet Series\"\n[7]: https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html \"Server Side Request Forgery Prevention - OWASP Cheat Sheet Series\"\n[8]: https://cheatsheetseries.owasp.org/cheatsheets/Nodejs_Security_Cheat_Sheet.html \"Nodejs Security - OWASP Cheat Sheet Series\"\n[9]: https://nvd.nist.gov/vuln/detail/cve-2024-29041?utm_source=chatgpt.com \"CVE-2024-29041 Detail - NVD\"\n[10]: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html \"HTTP Headers - OWASP Cheat Sheet Series\"\n[11]: https://expressjs.com/en/guide/error-handling.html \"Express error handling\"\n[12]: https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html \"Session Management - OWASP Cheat Sheet Series\"\n[13]: https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html \"File Upload - OWASP Cheat Sheet Series\"\n[14]: https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html \"OS Command Injection Defense - OWASP Cheat Sheet Series\"\n[15]: https://nodejs.org/en/learn/getting-started/security-best-practices \"Node.js — Security Best Practices\"\n[16]: https://docs.npmjs.com/cli/v9/commands/npm-audit/ \"npm-audit | npm Docs\"\n[17]: https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html \"Input Validation - OWASP Cheat Sheet Series\"\n[18]: https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html \"Unvalidated Redirects and Forwards - OWASP Cheat Sheet Series\"\n\n<!-- File: core/skills/builtin/security-best-practices/references/javascript-general-web-frontend-security.md (Tokens: ~9128 | Category: anthropic-skill) -->\n# Frontend JavaScript/TypeScript Web Security Spec (Vanilla Browser JS/TS, Modern Browsers)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new frontend JavaScript/TypeScript (no specific framework assumed).\n2. **Security review / vulnerability hunting** in existing frontend code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, hard-code, or commit secrets (API keys intended to be secret, private keys, passwords, OAuth refresh tokens, session tokens, cookies).\n  Notes:\n\n  * Frontend code is inherently observable by end users. If a value must remain secret, it must not be in browser-delivered code.\n  * If the project uses “public” keys (e.g., publishable analytics keys), they MUST be treated as non-secret and scoped accordingly.\n\n* MUST NOT “fix” security by disabling protections (e.g., weakening CSP with `unsafe-inline`/`unsafe-eval` without justification, removing origin checks for `postMessage`, switching to `innerHTML` for convenience, accepting arbitrary redirects/URLs, or turning off sanitization).\n\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and relevant HTML/CSP/config values that justify the claim.\n\n* MUST treat uncertainty honestly:\n\n  * Security headers (CSP, frame-ancestors, etc.) might be set by server/edge/CDN rather than in repo code. If not visible, report as “not visible here; verify at runtime/edge config.” (Also note that `<meta http-equiv=...>` only simulates a subset of headers; don’t assume other security headers exist just because a meta tag exists.) ([MDN Web Docs][1])\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new frontend JS/TS code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default browser APIs and proven libraries over custom security code (especially for HTML sanitization).\n* MUST avoid introducing new risky sinks (DOM XSS injection sinks like `innerHTML`, navigation to `javascript:` URLs, dynamic code execution via `eval`/`Function`, unsafe `postMessage`, unsafe third-party script loading, etc.). ([OWASP Cheat Sheet Series][2])\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a frontend repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. HTML entrypoints (`index.html`, server-rendered templates), script/style includes, and any CSP delivery (header vs meta). ([W3C][3])\n2. DOM XSS sinks (`innerHTML`, `document.write`, `insertAdjacentHTML`, event-handler attributes) and their data sources (URL params/hash, storage, postMessage, API responses). ([OWASP Cheat Sheet Series][2])\n3. Navigation/redirect handling (`window.location*`, link targets, URL allowlists) including `javascript:` URL hazards. ([MDN Web Docs][4])\n4. Cross-origin communication (`postMessage`, iframe embed patterns, sandboxing). ([MDN Web Docs][5])\n5. Storage of sensitive data (localStorage/sessionStorage) and assumptions about trust. ([OWASP Cheat Sheet Series][6])\n6. Third-party scripts / tag managers / CDNs, and integrity controls (SRI) and policy controls (CSP). ([OWASP Cheat Sheet Series][7])\n7. DOM clobbering gadgets and unsafe reliance on `window`/`document` named properties. ([OWASP Cheat Sheet Series][8])\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nExamples include:\n\n* URL-derived data: `location.href`, `location.search`, `location.hash`, `document.baseURI`, `new URLSearchParams(location.search)`, routing fragments. ([OWASP Cheat Sheet Series][2])\n* DOM content that may include user-controlled markup (comments, profiles, CMS content, markdown-to-HTML output, etc.), especially if inserted dynamically. ([OWASP Cheat Sheet Series][2])\n* `postMessage` event data (`event.data`) and metadata (`event.origin`) from other windows/frames. ([MDN Web Docs][5])\n* Browser storage: `localStorage`, `sessionStorage`, IndexedDB (contents can be attacker-influenced via XSS or local machine access; never treat as “trusted”). ([OWASP Cheat Sheet Series][6])\n* Any data returned from network calls (even if from “your API”), because it may contain stored attacker content that becomes dangerous only when inserted into the DOM. ([OWASP Cheat Sheet Series][2])\n\n### 2.2 Dangerous sink (DOM XSS / code execution sink)\n\nA sink is any API/operation that can execute script or interpret attacker-controlled strings as HTML/JS/URL in a security-sensitive way. High-signal sinks include:\n\n* HTML parsing / insertion: `innerHTML`, `outerHTML`, `insertAdjacentHTML`, `document.write`, `document.writeln`. ([OWASP Cheat Sheet Series][2])\n* Dynamic code execution: `eval`, `new Function`, `setTimeout(\"...\")`, `setInterval(\"...\")`. ([MDN Web Docs][10])\n* Navigation to script-bearing URLs (e.g., `javascript:`) via setters like `Location.href`/`window.location` (and via link `href` if attacker-controlled). ([MDN Web Docs][4])\n* Setting event handler attributes from strings, e.g. `setAttribute(\"onclick\", \"...\")`. ([OWASP Cheat Sheet Series][2])\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + function/class/module + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest baseline that prevents common frontend JS/TS security misconfigurations. Some items are “in repo” (HTML/JS) and some may live at the server/edge.\n\n### 3.1 Content Security Policy (CSP) baseline (SHOULD; MUST for high-risk apps)\n\n* SHOULD deliver CSP via HTTP response headers when possible.\n* MAY deliver CSP via an HTML `<meta http-equiv=\"Content-Security-Policy\" ...>` tag when you cannot set headers (e.g., purely static hosting constraints). ([MDN Web Docs][1])\n* If using CSP via `<meta http-equiv>`, MUST understand the limitations:\n\n  * The policy only applies to content that follows the meta element (so it must appear very early, before any scripts/resources you want governed). ([W3C][3])\n  * The following directives are **not supported** in a meta-delivered policy and will be ignored: `report-uri`, `frame-ancestors`, and `sandbox`. ([W3C][3])\n  * “Report-only” CSP cannot be set via a meta element. ([W3C][3])\n\nPractical baseline goals:\n\n* Avoid script sources `unsafe-inline` and `unsafe-eval` (they significantly weaken CSP’s value against XSS). ([MDN Web Docs][10])\n* Prefer nonce- or hash-based script policies if you need inline scripts. ([MDN Web Docs][10])\n* Consider enabling Trusted Types enforcement where feasible. ([MDN Web Docs][11])\n\n### 3.2 Third-party scripts baseline (SHOULD)\n\n* SHOULD minimize third-party script execution and treat it as equivalent privilege to first-party JS (it runs with your origin’s privileges). ([OWASP Cheat Sheet Series][7])\n* SHOULD use Subresource Integrity (SRI) for third-party scripts/styles loaded from CDNs. ([MDN Web Docs][12])\n\n### 3.3 Cross-window communication baseline (SHOULD)\n\n* SHOULD restrict `postMessage` communications to explicit origins, and validate both origin and message shape. ([MDN Web Docs][5])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### JS-XSS-001: Do not inject untrusted HTML into the DOM (avoid `innerHTML` and friends)\n\nSeverity: Critical if you can prove attacker-controlled input can reach these APIs; otherwise Medium\n\n\nRequired:\n\n* MUST treat `innerHTML`, `outerHTML`, and `insertAdjacentHTML` as dangerous sinks when their input can contain untrusted data. ([OWASP Cheat Sheet Series][2])\n* MUST prefer safe DOM APIs that do not parse HTML:\n\n  * `textContent` for text. ([OWASP Cheat Sheet Series][2])\n  * `document.createElement`, `appendChild`, `setAttribute` for non-event-handler attributes. ([OWASP Cheat Sheet Series][2])\n* If HTML insertion is truly required, SHOULD sanitize with a well-reviewed HTML sanitizer and strongly consider enforcing Trusted Types to confine usage to audited code paths. ([MDN Web Docs][11])\n\nInsecure patterns:\n\n* `el.innerHTML = userInput`\n* `el.insertAdjacentHTML('beforeend', userInput)`\n* `el.outerHTML = userInput`\n\nDetection hints:\n\n* Search for: `.innerHTML`, `.outerHTML`, `insertAdjacentHTML(`.\n* Trace the origin of inserted string: URL params/hash, postMessage, storage, API responses, DOM attributes. ([OWASP Cheat Sheet Series][2])\n\nFix:\n\n* Replace with `textContent` for plain text. ([OWASP Cheat Sheet Series][2])\n* For structured UI, build DOM nodes explicitly.\n* For “rich text” requirements:\n\n  * Sanitize using an allowlist-based sanitizer.\n  * Prefer returning safe “components” instead of arbitrary HTML strings.\n  * Use Trusted Types enforcement to ensure only `TrustedHTML` reaches sinks where supported. ([MDN Web Docs][11])\n\nMitigation:\n\n* Deploy a strict CSP and consider Trusted Types enforcement (`require-trusted-types-for 'script'`). ([MDN Web Docs][10])\n\nFalse positive notes:\n\n* If the string is provably constant or fully generated from trusted constants, it may be safe. Still prefer safer APIs.\n\n---\n\n### JS-XSS-002: Avoid `document.write` / `document.writeln` (XSS + document clobbering hazards)\n\nSeverity: Critical if you can prove attacker-controlled input can reach these APIs; otherwise Medium\n\nRequired:\n\n* MUST avoid `document.write()` and `document.writeln()` in production code (they are XSS vectors and can be abused with crafted HTML even if some browsers block injected `<script>` in certain situations). ([MDN Web Docs][13])\n* If legacy use is unavoidable, MUST ensure no untrusted input reaches these APIs and SHOULD enforce Trusted Types (`TrustedHTML`) where supported. ([MDN Web Docs][14])\n\nInsecure patterns:\n\n* `document.write(userInput)`\n* `document.writeln(getParam('q'))`\n\nDetection hints:\n\n* Search for `document.write(`, `document.writeln(`. ([OWASP Cheat Sheet Series][2])\n\nFix:\n\n* Replace with DOM manipulation (`createElement`, `appendChild`) or safe text insertion (`textContent`). ([OWASP Cheat Sheet Series][2])\n\nMitigation:\n\n* Strict CSP + Trusted Types enforcement reduces blast radius if a sink remains. ([MDN Web Docs][10])\n\n---\n\n### JS-XSS-003: Do not use string-to-code execution (`eval`, `new Function`, string timeouts)\n\nSeverity: Critical if you can prove attacker-controlled input can reach these APIs; otherwise Medium\n\nRequired:\n\n* MUST NOT pass untrusted data to:\n\n  * `eval()`\n  * `new Function(...)`\n  * `setTimeout(\"...\")` / `setInterval(\"...\")` with string arguments ([MDN Web Docs][10])\n* SHOULD avoid these APIs entirely in modern frontend code; refactor to non-eval logic. ([MDN Web Docs][10])\n* MUST NOT “fix CSP breakage” by adding `unsafe-eval` unless there is a documented, reviewed justification and compensating controls. ([MDN Web Docs][10])\n\nInsecure patterns:\n\n* `eval(userInput)`\n* `new Function(\"return \" + userInput)()`\n* `setTimeout(userInput, 0)` where userInput is a string\n\nDetection hints:\n\n* Search for `eval(`, `new Function`, `setTimeout(\"`, `setInterval(\"`.\n* Also search for construction of code strings used later.\n\nFix:\n\n* Replace dynamic code with:\n\n  * structured data + explicit branching/handlers,\n  * JSON parsing (`JSON.parse`) instead of `eval` for JSON. ([OWASP Cheat Sheet Series][2])\n\nMitigation:\n\n* CSP that blocks `eval()`-like APIs by default, and avoid `unsafe-eval`. ([MDN Web Docs][10])\n* Consider Trusted Types for controlled cases, but treat it as a hardening layer, not a license to keep eval patterns. ([MDN Web Docs][10])\n\n---\n\n### JS-XSS-004: Do not set event handler attributes from strings (e.g., `setAttribute(\"onclick\", \"...\")`)\n\nSeverity: High\n\nRequired:\n\n* MUST NOT use `setAttribute(\"on…\", string)` or similar patterns with untrusted data; this coerces strings into executable code in the event-handler context. ([OWASP Cheat Sheet Series][2])\n* SHOULD prefer `addEventListener` with function references.\n\nInsecure patterns:\n\n* `el.setAttribute(\"onclick\", userInput)`\n* `el.onclick = userControlledString` (string assignment)\n\nDetection hints:\n\n* Search for `.setAttribute(\"on`, `.onclick =`, `.onmouseover =`, etc.\n* Trace whether RHS can be influenced by URL/hash/storage/postMessage. ([OWASP Cheat Sheet Series][2])\n\nFix:\n\n* Replace with `addEventListener(\"click\", () => { ... })`.\n* If dynamic dispatch is needed, use an allowlisted mapping from identifiers to functions (no string eval). ([OWASP Cheat Sheet Series][2])\n\n---\n\n### JS-URL-001: Sanitize and allowlist URLs before navigation (especially `window.location` / `location.replace`)\n\nSeverity: Low (High if you can prove an attacker can fully control the URL)\n\nIMPORTANT: This can cause a lot of false positives. Please perform extra analysis to determine if the url is fully attacker controlled. If not fully attacker controlled, then this is informational at best.\n\nNOTE: It may be important functionality to be able to redirect to any given url. If that is the goal of the feature, then at a minimum, ensure it checks the schema even if the origin is allowed to be anything.\n\nRequired:\n\n* MUST treat any assignment to navigation targets as security-sensitive:\n\n  * `window.location = ...`\n  * `location.href = ...`\n  * `location.assign(...)`\n  * `location.replace(...)` ([MDN Web Docs][4])\n* MUST prevent navigation to `javascript:` URLs (and generally other script-bearing/active schemes), especially when input is derived from URL params, storage, or messages. ([MDN Web Docs][4]). Only allow `http:` and `https:`.\n* SHOULD validate/allowlist the destination. A safe baseline is:\n\n  * Allow only same-origin relative paths, OR\n  * Allow only a strict allowlist of origins and protocols (typically `https:` and optionally `http:` for localhost dev). ([OWASP Cheat Sheet Series][8])\n\nInsecure patterns:\n\n* `location.replace(getParam(\"next\"))`\n* `window.location = userSuppliedUrl`\n* `location.assign(window.redirectTo || \"/\")` where `redirectTo` can be clobbered or attacker-set ([OWASP Cheat Sheet Series][8])\n\nDetection hints:\n\n* Search for `window.location`, `location.href`, `location.assign`, `location.replace`.\n* Search for common redirect parameters: `next`, `returnTo`, `redirect`, `url`, `continue`.\n* Search for `javascript:` literal usage. ([MDN Web Docs][4])\n\nFix:\n\n* Parse and validate with `new URL(value, location.origin)` and then enforce:\n\n  * `url.protocol` in `{ \"https:\" }` (and only include `http:` in explicit dev-only code paths),\n  * `url.origin` equals `location.origin` for internal redirects, or in a strict allowlist for external redirects,\n  * optionally allow only specific path prefixes. ([MDN Web Docs][4])\n* If validation fails, navigate to a safe default (home/dashboard).\n\nMitigation:\n\n* Deploy strict CSP and Trusted Types enforcement to reduce the impact of DOM XSS sinks, but note that Trusted Types do not prevent every possible unsafe navigation scenario on their own. ([W3C][15])\n\nFalse positive notes:\n\nIMPORTANT: This can cause a lot of false positives. Please perform extra analysis to determine if the url is fully attacker controlled. If not fully attacker controlled, then this is informational at best.\n\n* Some apps intentionally support external redirects (SSO, payment flows). Those MUST be allowlisted and documented.\n\n---\n\n### JS-URL-002: Sanitize URLs before inserting into DOM URL contexts (`href`, `src`, etc.)\n\nSeverity: Low (High if you can prove an attacker can fully control the URL)\n\nIMPORTANT: This can cause a lot of false positives. Please perform extra analysis to determine if the url is fully attacker controlled. If not fully attacker controlled, then this is informational at best.\n\nRequired:\n\n* MUST treat setting URL-bearing DOM attributes/properties as security-sensitive, especially:\n\n  * `a.href`, `img.src`, `script.src`, `iframe.src`, `form.action`, `link.href`.\n* MUST prevent script-bearing schemes (`javascript:` and other active schemes) when values can be attacker-influenced. ([MDN Web Docs][4])\n* SHOULD prefer setting properties (e.g., `a.href = url.toString()`) after parsing and validation, rather than string concatenation.\n\nInsecure patterns:\n\n* `link.href = getParam(\"u\")`\n* `el.setAttribute(\"href\", userInput)` without validation\n* constructing URLs via concatenation with untrusted pieces\n\nDetection hints:\n\n* Search for `.href =`, `.src =`, `.action =`, `setAttribute(\"href\"`, `setAttribute(\"src\"`.\n* Search for `javascript:` / `data:` usage in URLs. ([MDN Web Docs][4])\n\nIMPORTANT: This can cause a lot of false positives. Please perform extra analysis to determine if the url is fully attacker controlled. If not fully attacker controlled, then this is informational at best.\n\nFix:\n\n* Use `new URL(...)` and validate:\n\n  * protocol allowlist\n  * avoid passing user-provided values into `<script src>` at all (treat as code execution). ([OWASP Cheat Sheet Series][8])\n\n---\n\n### JS-CSP-001: Use CSP; meta delivery is allowed\n\nSeverity: Medium to High (depends on threat model; High when handling untrusted content)\n\nNOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n\nRequired:\n\n* SHOULD deploy a CSP as a major defense-in-depth against XSS. ([MDN Web Docs][10])\n* MAY provide CSP via `<meta http-equiv=\"Content-Security-Policy\" ...>` when headers are not available. ([MDN Web Docs][1])\n* If CSP is delivered via meta, MUST:\n\n  * place it early (before scripts/resources you want governed), and\n  * not rely on unsupported directives in meta policies (`report-uri`, `frame-ancestors`, `sandbox`). ([W3C][3])\n* MUST avoid adding `unsafe-inline` as a “quick fix” for CSP issues unless explicitly required and reviewed (it defeats much of CSP’s purpose). ([MDN Web Docs][10])\n* MUST avoid adding `unsafe-eval` unless explicitly required and reviewed (it allows eval-like APIs that are commonly abused). ([MDN Web Docs][10])\n\nInsecure patterns:\n\n* No CSP present anywhere (repo HTML or server/edge) for an app that renders untrusted content.\n* CSP includes `script-src 'unsafe-inline'` and/or `script-src 'unsafe-eval'` without strong justification. ([MDN Web Docs][10])\n* CSP delivered via meta but includes `frame-ancestors` (it will be ignored in meta). ([W3C][3])\n\nDetection hints:\n\n* Search HTML for `<meta http-equiv=\"Content-Security-Policy\"`.\n* Search server/edge configs for `Content-Security-Policy` header.\n* If CSP is only in meta, check it appears before any `<script>` tags you want governed. ([W3C][3])\n\nFix:\n\n* Prefer header-delivered CSP at the server/edge.\n* If constrained to meta, keep a strong allowlist CSP and document the limitations; implement clickjacking protections (e.g., `frame-ancestors`) at the server/edge, not in meta. ([W3C][3])\n\n---\n\n### JS-CSP-002: Prefer strict CSP (nonces/hashes); avoid inline/eval patterns in code\n\nSeverity: Medium\n\nNOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n\nRequired:\n\n* SHOULD design frontend code to work under a strict CSP:\n\n  * avoid inline scripts and inline event handlers,\n  * avoid eval-like APIs (see JS-XSS-003),\n  * allow scripts via nonce or hash when needed. ([MDN Web Docs][10])\n\nInsecure patterns:\n\n* Large amounts of inline script blocks and inline `onclick=\"...\"` handlers.\n* Libraries that require `unsafe-eval`.\n\nDetection hints:\n\n* Search for `<script>` blocks with inline code, `onclick=\"`, `onload=\"`, etc.\n* Search for CSP directives containing `unsafe-inline` or `unsafe-eval`. ([MDN Web Docs][10])\n\nFix:\n\n* Move inline scripts into external JS files (same-origin).\n* Use nonces/hashes for any unavoidable inline blocks. ([MDN Web Docs][10])\n\n---\n\n### JS-TT-001: Use Trusted Types to reduce DOM XSS attack surface (where supported)\n\nSeverity: Low\n\nRequired:\n\n* SHOULD consider enabling Trusted Types enforcement with CSP `require-trusted-types-for 'script'` to make many DOM XSS sinks reject raw strings. ([MDN Web Docs][11])\n* If using Trusted Types, SHOULD also use the CSP `trusted-types` directive to restrict which policies can be created (reduces policy sprawl and improves auditability). ([MDN Web Docs][16])\n* MUST keep Trusted Types policy code small, heavily reviewed, and used as the only path to produce trusted values for sinks. ([W3C][15])\n\nInsecure patterns:\n\n* “Trusted Types enabled” but policy simply returns input unchanged (no sanitization/validation).\n* Many ad-hoc policies created across the codebase without restriction.\n* Belief that Trusted Types alone prevents all unsafe navigations or all XSS classes. (It targets DOM injection sinks; it is not a universal sandbox.) ([W3C][15])\n\nDetection hints:\n\n* Search for CSP directives: `require-trusted-types-for` and `trusted-types`.\n* Search code for `trustedTypes.createPolicy(` and inspect policy implementations. ([MDN Web Docs][11])\n\nFix:\n\n* Add a small set of well-reviewed policies (e.g., `createHTML` that sanitizes).\n* Restrict allowed policies via `trusted-types <policyName...>`.\n* Migrate sinks to require `TrustedHTML` / `TrustedScriptURL` as appropriate. ([MDN Web Docs][11])\n\n---\n\n### JS-MSG-001: `postMessage` must use strict origin validation and explicit targetOrigin\n\nSeverity: Medium (High if dangerous behavior can be triggered via postMessage)\n\nRequired:\n\n* When sending messages, MUST set an explicit `targetOrigin` (not `*`) to avoid sending data to an unexpected origin after redirects or window origin changes. ([MDN Web Docs][5])\n* When receiving messages, MUST:\n\n  * Validate `event.origin` exactly against an allowlist of expected origins (no substring matching). ([OWASP Cheat Sheet Series][6])\n  * Consider validating `event.source` (expected window reference) when applicable. ([MDN Web Docs][5])\n  * Validate `event.data` structure (schema/shape) and treat it purely as data (never evaluate it as code and never insert into DOM with `innerHTML`). ([OWASP Cheat Sheet Series][6])\n\nInsecure patterns:\n\n* `otherWindow.postMessage(payload, \"*\")`\n* `window.addEventListener(\"message\", (e) => { doSomething(e.data) })` with no `origin` check\n* `if (e.origin.includes(\"trusted.com\"))` (substring checks)\n* `el.innerHTML = e.data` ([OWASP Cheat Sheet Series][6])\n\nDetection hints:\n\n* Search for `postMessage(`, `addEventListener(\"message\"`, `onmessage =`.\n* Audit all handlers for explicit allowlist checks on `event.origin`. ([OWASP Cheat Sheet Series][6])\n\nFix:\n\n* Define an allowlist:\n\n  * `const ALLOWED = new Set([\"https://app.example.com\", \"https://accounts.example.com\"]);`\n  NOTE: For ease of development, you can use the current page's origin `window.location.origin` as a safe default origin.\n* On receive:\n\n  * `if (!ALLOWED.has(event.origin)) return;`\n  * Validate `event.data` with a strict schema and reject unknown/extra fields.\n* On send:\n\n  * use the exact expected origin string as `targetOrigin`. ([OWASP Cheat Sheet Series][6])\n\nMitigation:\n\n* Combine with a strict CSP and avoid DOM sinks in message paths. ([MDN Web Docs][10])\n\n---\n\n### JS-STORAGE-001: Web Storage is not a safe place for secrets (and is attacker-influencable)\n\nSeverity: Low\n\nRequired:\n\n* MUST NOT store sensitive secrets or session identifiers in `localStorage` (or `sessionStorage`) if compromise would matter; a single XSS can exfiltrate everything in storage. ([OWASP Cheat Sheet Series][6])\n* MUST treat values read from storage as untrusted input (attackers can load malicious values into storage via XSS). ([OWASP Cheat Sheet Series][6])\n* SHOULD prefer server-set cookies with `HttpOnly` for session identifiers (JS cannot set `HttpOnly`, so avoid storing session IDs in JS-accessible storage). ([OWASP Cheat Sheet Series][6])\n* SHOULD avoid hosting multiple unrelated apps on the same origin if they rely on storage separation (storage is origin-wide). ([OWASP Cheat Sheet Series][6])\n\nInsecure patterns:\n\n* `localStorage.setItem(\"access_token\", token)`\n* `localStorage.setItem(\"session\", sessionId)`\n* Assuming `localStorage` is “trusted because same-origin.”\n\nDetection hints:\n\n* Search for `localStorage.getItem`, `localStorage.setItem`, `sessionStorage.*`.\n* Flag storage keys named `token`, `jwt`, `session`, `auth`, `refresh`. ([OWASP Cheat Sheet Series][6])\n\nFix:\n\n* Use server-managed sessions or short-lived tokens delivered and rotated securely, with careful XSS defenses (CSP/Trusted Types) and minimal JS exposure.\n* If storage must be used for non-sensitive state, keep it non-auth and validate/escape before use.\n\n---\n\n### JS-SUPPLY-001: Third-party JavaScript is a major supply-chain risk; minimize and control it\n\nSeverity: Low\n\nRequired:\n\n* MUST treat third-party JS as equivalent to first-party JS in privilege (it can execute arbitrary code in your origin and access DOM data). ([OWASP Cheat Sheet Series][7])\n* SHOULD minimize third-party scripts and prefer:\n\n  * self-hosting / script mirroring,\n  * strict CSP allowlists,\n  * SRI for any CDN-hosted scripts,\n  * ongoing monitoring for unexpected changes. ([OWASP Cheat Sheet Series][7])\n\nInsecure patterns:\n\n* Loading arbitrary remote scripts from many vendors without review.\n* Using tag managers that can dynamically inject scripts with no integrity controls.\n* Allowing scripts from broad wildcards in CSP (e.g., `script-src *`). ([MDN Web Docs][10])\n\nDetection hints:\n\n* Search HTML for `<script src=\"https://...\">` and `tag manager` snippets.\n* Search CSP `script-src` sources for wildcards or overly broad domains.\n* Search for dynamic script injection: `document.createElement(\"script\")`, `script.src = ...`, `appendChild(script)`. ([OWASP Cheat Sheet Series][8])\n\nFix:\n\n* Remove unnecessary third-party tags.\n* Self-host or mirror scripts where possible.\n* Lock down CSP `script-src` to the smallest set of trusted sources.\n* Add SRI for CDN scripts/styles. ([OWASP Cheat Sheet Series][7])\n\n---\n\n### JS-SRI-001: Use Subresource Integrity (SRI) for third-party scripts/styles\n\nSeverity: Low\n\nRequired:\n\n* SHOULD use SRI to ensure browsers only load third-party resources if they match an expected cryptographic hash. ([MDN Web Docs][12])\n* MUST update SRI hashes whenever the underlying resource changes (pin versions; avoid “latest” URLs).\n\nInsecure patterns:\n\n* `<script src=\"https://cdn.example.com/lib.js\"></script>` with no `integrity`.\n* Loading `latest` or unpinned third-party resources.\n\nDetection hints:\n\n* Search for `<script src=\"https://` and `<link rel=\"stylesheet\" href=\"https://` without `integrity=`.\n* Check whether `integrity` is present and uses strong hashes (sha256/384/512 are typical). ([MDN Web Docs][12])\n\nFix:\n\n* Add `integrity=\"sha384-...\"` (or appropriate) and ensure proper CORS mode where needed.\n* Prefer self-hosting critical libraries.\n\n---\n\n### FS-DOMC-001: Prevent DOM clobbering (avoid relying on `window`/`document` named properties)\n\nSeverity: Medium to High (can become Critical if it enables script loading or `javascript:` navigation)\n\nRequired:\n\n* MUST NOT rely on implicit global variables or `window.someName` / `document.someName` lookups that can be clobbered by injected HTML elements with matching `id`/`name`. ([OWASP Cheat Sheet Series][8])\n* MUST avoid patterns like `let x = window.redirectTo || \"/safe\"; location.assign(x);` where `redirectTo` could be clobbered to an `<a>` element whose `href` is attacker-controlled (including `javascript:`). ([OWASP Cheat Sheet Series][8])\n* SHOULD use explicit variable declarations, local scope, and explicit DOM queries (`getElementById`) rather than named property access. ([OWASP Cheat Sheet Series][8])\n* If the app inserts user-controlled markup (even sanitized), SHOULD ensure sanitization strategies consider `id`/`name` collisions. ([OWASP Cheat Sheet Series][8])\n\nInsecure patterns:\n\n* `const cfg = window.config || {};` used for security-sensitive URLs.\n* `const redirect = window.redirectTo || \"/\"; location.assign(redirect);` ([OWASP Cheat Sheet Series][8])\n* Loading scripts from `window.*` config values without strict validation.\n\nDetection hints:\n\n* Search for `window.` and `document.` used as config stores (especially `||` fallback patterns).\n* Search for usage of `location.assign/replace` with variables that come from `window`/`document` properties.\n* Search for dynamic script creation (`createElement('script')`) where `.src` comes from a non-local variable. ([OWASP Cheat Sheet Series][8])\n\nFix:\n\n* Store config in module-scoped constants (not on `window`/`document`) and pass it explicitly.\n* Validate any URL-like config with protocol/origin allowlists (see FEJS-URL-001). ([OWASP Cheat Sheet Series][8])\n* Consider hardening: sanitization, CSP, and (in limited cases) freezing sensitive objects, but treat these as defense-in-depth, not a substitute for safe coding patterns. ([OWASP Cheat Sheet Series][8])\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* DOM XSS sinks:\n\n  * `.innerHTML`, `.outerHTML`, `insertAdjacentHTML(`\n  * `document.write(`, `document.writeln(` ([OWASP Cheat Sheet Series][2])\n\n* Dangerous navigation / URL sinks:\n\n  * `window.location`, `location.href`, `location.assign`, `location.replace`\n  * `javascript:` literals (and other suspicious schemes like `data:text/html`) ([MDN Web Docs][4])\n\n* String-to-code execution:\n\n  * `eval(`, `new Function`, `setTimeout(\"`, `setInterval(\"` ([MDN Web Docs][10])\n\n* Event-handler string injection:\n\n  * `.setAttribute(\"on`, `.onclick =`, `.onload =` with strings ([OWASP Cheat Sheet Series][2])\n\n* `postMessage`:\n\n  * `postMessage(` with `\"*\"` as targetOrigin\n  * `addEventListener(\"message\"` without strict `event.origin` allowlist checks ([MDN Web Docs][5])\n\n* Storage:\n\n  * `localStorage.setItem(` / `getItem(`, `sessionStorage.*`\n  * keys containing `token`, `jwt`, `session`, `auth`, `refresh` ([OWASP Cheat Sheet Series][6])\n\n* CSP and related:\n\n  * `Content-Security-Policy` header config (server/edge)\n  * `<meta http-equiv=\"Content-Security-Policy\" ...>`\n  * CSP containing `unsafe-inline` or `unsafe-eval`\n  * `require-trusted-types-for` / `trusted-types` directives ([MDN Web Docs][1])\n\n* Third-party scripts:\n\n  * `<script src=\"https://...\">` without `integrity=`\n  * Tag manager snippets and dynamic script injection code paths ([MDN Web Docs][12])\n\n\n* DOM clobbering gadgets:\n\n  * `window.<name> || ...` and `document.<name> || ...` patterns\n  * security-sensitive usage of `window`/`document` properties as config sources ([OWASP Cheat Sheet Series][8])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted),\n* sink type (HTML parse, navigation, code execution, message handling, storage),\n* protective controls present (CSP, Trusted Types, sanitizers, strict allowlists, schema validation).\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary standards / platform docs:\n\n* W3C Content Security Policy Level 2 (HTML `<meta>` delivery restrictions; unsupported directives in meta CSP): `https://www.w3.org/TR/CSP2/` ([W3C][3])\n* MDN: CSP Guide (strict CSP, nonces/hashes, `unsafe-inline`/`unsafe-eval`, eval blocking): `https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP` ([MDN Web Docs][10])\n* MDN: `<meta http-equiv>` (CSP via meta and warning about meta-based security headers): `https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/meta/http-equiv` ([MDN Web Docs][1])\n* MDN: `frame-ancestors` (and note it’s not supported in `<meta>`): `https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/frame-ancestors` ([MDN Web Docs][18])\n\nDOM XSS and dangerous sinks:\n\n* OWASP: DOM Based XSS Prevention Cheat Sheet (dangerous sinks + safe patterns like `textContent`): `https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][2])\n* MDN: `innerHTML` (security considerations): `https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML` ([MDN Web Docs][19])\n* MDN: `insertAdjacentHTML` (security considerations): `https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML` ([MDN Web Docs][20])\n* MDN: `document.write()` / `document.writeln()` (security considerations): `https://developer.mozilla.org/en-US/docs/Web/API/Document/write` and `https://developer.mozilla.org/en-US/docs/Web/API/Document/writeln` ([MDN Web Docs][13])\n\nURL scheme hazards:\n\n* MDN: `javascript:` URLs (execution on navigation; discouraged; references `window.location`): `https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Schemes/javascript` ([MDN Web Docs][4])\n\nTrusted Types:\n\n* W3C: Trusted Types spec (DOM XSS sinks include `Element.innerHTML` and `Location.href` setters; goals and limitations): `https://www.w3.org/TR/trusted-types/` ([W3C][15])\n* MDN: `require-trusted-types-for` directive: `https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/require-trusted-types-for` ([MDN Web Docs][11])\n* MDN: `trusted-types` directive: `https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/trusted-types` ([MDN Web Docs][16])\n\nCross-window messaging:\n\n* MDN: `window.postMessage` (security guidance: specify targetOrigin; validate origin): `https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage` ([MDN Web Docs][5])\n* OWASP: HTML5 Security Cheat Sheet (Web Messaging guidance: explicit origin, strict checks, no `innerHTML`): `https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][6])\n\nThird-party scripts and integrity:\n\n* OWASP: Third Party JavaScript Management Cheat Sheet (risks and mitigations including SRI/mirroring): `https://cheatsheetseries.owasp.org/cheatsheets/Third_Party_Javascript_Management_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][7])\n* MDN: Subresource Integrity overview: `https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity` ([MDN Web Docs][12])\n* W3C: Subresource Integrity spec: `https://www.w3.org/TR/sri-2/` ([W3C][21])\n\nDOM clobbering:\n\n* OWASP: DOM Clobbering Prevention Cheat Sheet (named property access risk; example attacks involving `location.assign` and `javascript:`): `https://cheatsheetseries.owasp.org/cheatsheets/DOM_Clobbering_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][8])\n\n[1]: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/meta/http-equiv \"https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/meta/http-equiv\"\n[2]: https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html\"\n[3]: https://www.w3.org/TR/CSP2/ \"Content Security Policy Level 2\"\n[4]: https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Schemes/javascript \"javascript: URLs - URIs | MDN\"\n[5]: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage \"https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage\"\n[6]: https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html\"\n[7]: https://cheatsheetseries.owasp.org/cheatsheets/Third_Party_Javascript_Management_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Third_Party_Javascript_Management_Cheat_Sheet.html\"\n[8]: https://cheatsheetseries.owasp.org/cheatsheets/DOM_Clobbering_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/DOM_Clobbering_Prevention_Cheat_Sheet.html\"\n[9]: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/noopener \"https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/noopener\"\n[10]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP \"https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP\"\n[11]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/require-trusted-types-for \"https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/require-trusted-types-for\"\n[12]: https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity \"https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity\"\n[13]: https://developer.mozilla.org/en-US/docs/Web/API/Document/write \"https://developer.mozilla.org/en-US/docs/Web/API/Document/write\"\n[14]: https://developer.mozilla.org/en-US/docs/Web/API/Document/writeln \"https://developer.mozilla.org/en-US/docs/Web/API/Document/writeln\"\n[15]: https://www.w3.org/TR/trusted-types/ \"https://www.w3.org/TR/trusted-types/\"\n[16]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/trusted-types \"https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/trusted-types\"\n[18]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/frame-ancestors \"https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/frame-ancestors\"\n[19]: https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML \"https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML\"\n[20]: https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML \"https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML\"\n[21]: https://www.w3.org/TR/sri-2/ \"https://www.w3.org/TR/sri-2/\"\n\n<!-- File: core/skills/builtin/security-best-practices/references/javascript-jquery-web-frontend-security.md (Tokens: ~8234 | Category: anthropic-skill) -->\n# jQuery Frontend Security Spec (jQuery 4.0.x, modern browsers)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new jQuery-based frontend code.\n2. **Security review / vulnerability hunting** in existing jQuery-based code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session tokens, refresh tokens, CSRF tokens, session cookies).\n* MUST treat the browser as an attacker-controlled environment:\n\n  * Frontend checks (UI gating, “disable button”, hidden fields, client-side validation) MUST NOT be treated as authorization or a security boundary.\n  * Server-side authorization and validation MUST exist even if frontend is “correct”.\n* MUST NOT “fix” security by disabling protections (e.g., relaxing CSP to allow `unsafe-inline`, enabling JSONP “because it works”, adding broad CORS, disabling sanitization, suppressing security checks).\n* MUST provide evidence-based findings during audits: cite file paths, code snippets, and relevant configuration values.\n* MUST treat uncertainty honestly: if a protection might exist at the edge (CDN/WAF/reverse proxy headers like CSP), report it as “not visible in repo; verify at runtime/config”.\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new jQuery code or modify existing jQuery code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default patterns: text insertion, DOM node construction, allowlists, and proven sanitization libraries over custom escaping.\n* MUST avoid introducing new risky sinks (HTML string building, dynamic script loading, JSONP, inline script/event-handler attributes, unsafe URL assignment, unsafe object merging).\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a repo that uses jQuery (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in the structured format (see §2.3).\n\nRecommended audit order:\n\n1. jQuery sourcing, versions, and dependency hygiene (script tags, lockfiles, CDN usage, SRI).\n2. CSP / Trusted Types / security headers posture (in repo and at runtime if observable).\n3. DOM XSS: untrusted sources → jQuery sinks (`.html`, `.append`, `$(\"<…>\")`, `.load`, etc.).\n4. Script execution sinks: JSONP, `dataType:\"script\"`, `$.getScript`, dynamic `<script>` insertion.\n5. URL/attribute assignment (`href`, `src`, `style`, `on*` attributes).\n6. Prototype pollution / unsafe object merging (`$.extend` patterns).\n7. AJAX auth patterns + CSRF for cookie-based sessions.\n8. Third-party plugins and untrusted content rendering paths (comments, WYSIWYG, markdown-to-HTML).\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nExamples include:\n\n* Any data from the server that originates from users (user profiles, comments, “display name”, rich text, filenames).\n* Data from third-party APIs or services.\n* Browser-controlled sources:\n\n  * `location.href`, `location.search`, `location.hash`\n  * `document.URL`, `document.baseURI`, `document.referrer`\n  * `window.name`\n  * `localStorage` / `sessionStorage`\n  * `postMessage` event data (unless strict origin and schema validation exists)\n  * Any DOM content that could have been injected previously (stored XSS)\n\n### 2.2 High-risk “sinks” in jQuery contexts\n\nA sink is a code path where untrusted input can become interpreted as executable code or HTML.\n\nKey jQuery sink categories:\n\n* HTML insertion / parsing:\n\n  * DOM manipulation methods that accept HTML strings such as `.html()`, `.append()`, and related methods (see CVE notes below). ([NVD][1])\n  * `$(htmlString)` (when the argument can be interpreted as HTML markup).\n  * `jQuery.parseHTML(html, …, keepScripts)` especially with `keepScripts=true`. ([jQuery API][2])\n  * `.load(url)` (loads HTML into DOM; has special script execution behavior). ([jQuery API][3])\n* Script execution / dynamic code loading:\n\n  * `$.getScript()` / `$.ajax({ dataType: \"script\" })` (executes fetched JavaScript). ([jQuery API][4])\n  * JSONP (`dataType: \"jsonp\"` or implicit JSONP behavior) (executes remote JavaScript as a response). ([jQuery API][5])\n  * `eval`, `new Function`, `setTimeout(\"…\")`, `setInterval(\"…\")`, `$.globalEval` (if present)\n* Dangerous attribute assignment:\n\n  * Assigning untrusted strings to `href`, `src`, `srcdoc`, `style`, or event-handler attributes (`onload`, `onclick`, etc.)\n  * `javascript:` URLs are particularly dangerous and discouraged. ([MDN Web Docs][6])\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + function/component + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common jQuery-related security failures.\n\n### 3.1 Use a supported, patched jQuery version (MUST)\n\n* MUST use a supported jQuery major version and keep it updated.\n* As of 2026-01-27, the jQuery project ships jQuery 4.0.0 as the latest major release. ([blog.jquery.com][7])\n* If you must support very old browsers (notably IE < 11), jQuery 4 does not support them and you may need to stay on jQuery 3.x; treat this as a higher risk posture and patch aggressively. ([blog.jquery.com][7])\n\n### 3.2 Load jQuery safely (MUST)\n\n* MUST load jQuery only from:\n\n  * Your own build pipeline (bundled via npm/yarn + lockfile), or\n  * The official jQuery CDN / a trusted CDN with Subresource Integrity (SRI) enabled.\n* If loading from a CDN, SHOULD use SRI (`integrity`) and correct `crossorigin` settings; the jQuery project explicitly supports and recommends SRI on its CDN. (Retrieved from [jquery.com][8])\n\n### 3.3 CSP + Trusted Types (SHOULD, and MUST where available/required by policy)\n\n* SHOULD deploy a Content Security Policy (CSP) that reduces XSS impact (especially `script-src` restrictions and avoiding `unsafe-inline`). If not done through HTTP server, this can be done through the `<meta http-equiv=\"Content-Security-Policy\" content=\"...\">` tag. ([OWASP Cheat Sheet Series][9]) NOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n* SHOULD consider Trusted Types as a strong defense-in-depth against DOM XSS. ([W3C][10])\n* If you deploy the CSP directive `require-trusted-types-for`, then code MUST route DOM-injection through Trusted Types policies. ([MDN Web Docs][11])\n* Note: jQuery 4.0 explicitly added Trusted Types support so that TrustedHTML can be used with jQuery manipulation methods without violating `require-trusted-types-for`. ([blog.jquery.com][7])\n\n### 3.4 Security headers and cookie posture (defense in depth; SHOULD)\n\nEven though these are typically set server-side, they materially reduce the blast radius of jQuery-related mistakes. However if the context is only the frontend web application, these cannot be acted on.\n\n* SHOULD set common security headers (CSP, `X-Content-Type-Options: nosniff`, clickjacking protection via `frame-ancestors` / `X-Frame-Options`, `Referrer-Policy`). ([OWASP Cheat Sheet Series][12])\n* SHOULD avoid storing long-lived secrets/tokens in places accessible to JavaScript (like `localStorage`) unless the threat model explicitly accepts “XSS == account takeover”. This is not jQuery-specific, but jQuery-heavy DOM manipulation increases the chance of DOM XSS regressions; reduce the payoff.\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### JQ-SUPPLY-001: jQuery MUST be patched; do not run known vulnerable versions\n\nSeverity: Medium (High if internet-facing app AND version is known-vulnerable)\n\nNOTE: Before performing an upgrade, get concent from the user and try to understand if they have reasons to keep it back. Upgrading can break applications in unexpected ways. Report and recommend upgrades rather than just performing them.\n\nRequired:\n\n* MUST NOT use jQuery versions with known high-impact vulnerabilities when a patched version exists.\n* MUST upgrade past:\n\n  * CVE-2019-11358 (prototype pollution in jQuery before 3.4.0). ([NVD][13])\n  * CVE-2020-11022 / CVE-2020-11023 (XSS risks in DOM manipulation methods when handling untrusted HTML; patched in 3.5.0). ([NVD][1])\n\nInsecure patterns:\n\n* Script tags or package manifests referencing old jQuery (e.g., `jquery-1.*`, `jquery-2.*`, `jquery-3.3.*`, `jquery-3.4.*`, `jquery-3.4.1`, etc.).\n* Bundled vendor directories containing old minified jQuery without an upgrade path.\n\nDetection hints:\n\n* Search HTML/templates for `jquery-` and parse version strings.\n* Check `package.json`, `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`.\n* Check `vendor/`, `public/`, `static/`, `assets/`, `wwwroot/` for `jquery*.js`.\n\nFix:\n\n* Upgrade to current jQuery (prefer latest stable major; as of 2026-01-27, 4.0.0 is current). ([blog.jquery.com][7])\n* If upgrade is constrained, at minimum upgrade beyond the CVE thresholds and add compensating controls (strong CSP, strict sanitization, remove risky APIs like JSONP, remove deep-extend of untrusted objects).\n\nNotes:\n\n* If a product requirement forces old versions, report as “accepted risk requiring compensating controls”.\n\n---\n\n### JQ-SUPPLY-002: Third-party script loading SHOULD use integrity and trusted origins\n\nSeverity: High\n\nRequired:\n\n* MUST load jQuery and plugins only from trusted origins.\n* If loaded from CDN, SHOULD use SRI (`integrity`) and correct `crossorigin` handling. ([jquery.com][8])\n\nInsecure patterns:\n\n* `<script src=\"https://…/jquery.min.js\"></script>` with no `integrity`.\n* Loading jQuery from random third-party CDNs without an explicit trust decision.\n\nDetection hints:\n\n* Scan HTML for `<script src=` and check for `integrity=` + `crossorigin=`.\n* Identify dynamic script insertion with untrusted URLs (see JQ-EXEC-001).\n\nFix:\n\n* Prefer bundling via npm + lockfile.\n* If using CDN, copy official script tag (jQuery CDN supports SRI). ([jquery.com][8])\n\nNote: If unable to get the correct SRI tag, skip this step but tell the user. If you end up using the wrong one the app will not function. In that case remove it and inform the user.\n\n---\n\n### JQ-XSS-001: Untrusted data MUST NOT be inserted as HTML via jQuery DOM-manipulation methods\n\nSeverity: High (if attacker-controlled content reaches these sinks)\n\nRequired:\n\n* MUST treat any HTML string insertion as a code execution boundary.\n* MUST use safe alternatives for untrusted text:\n\n  * `.text(untrusted)` (text, not HTML). ([jQuery API][14])\n  * `.val(untrusted)` for form fields. ([jQuery API][15])\n  * Create elements and set text/attributes safely instead of concatenating HTML strings.\n\nInsecure patterns (examples):\n\n* `$(selector).html(untrusted)`\n* `$(selector).append(untrusted)`\n* `$(selector).before(untrusted)` / `.after(untrusted)` / `.replaceWith(untrusted)` / `.wrap(untrusted)` (and similar)\n* Building markup: `\"<div>\" + untrusted + \"</div>\"` then passing to jQuery\n\nDetection hints:\n\n* Grep for: `.html(`, `.append(`, `.prepend(`, `.before(`, `.after(`, `.replaceWith(`, `.wrap(`, `.wrapAll(`, `.wrapInner(`\n* Trace dataflow into these calls from sources in §2.1.\n\nFix:\n\n* Replace with `.text()` / `.val()` or node construction:\n\n  * `const $el = $(\"<span>\").text(untrusted); container.append($el);`\n* If the output must contain limited markup, see JQ-XSS-002 (sanitization).\n\nNotes:\n\n* Older jQuery versions had additional edge cases even when attempting sanitization; patched in 3.5.0+. Still: never rely on “string sanitization” alone—prefer structured creation or proven sanitizers. ([GitHub][16])\n\n---\n\n### JQ-XSS-002: If rendering user-controlled HTML is required, it MUST be sanitized with a proven HTML sanitizer\n\nSeverity: Medium (High if rich HTML is attacker-controlled and sanitizer is weak/misconfigured)\n\nRequired:\n\n* MUST NOT “roll your own” HTML sanitizer with regexes.\n* If user-controlled HTML must be displayed (e.g., rich text comments), MUST sanitize using a well-maintained HTML sanitizer and a restrictive allowlist.\n\n  * DOMPurify is a common choice; use conservative configuration and keep it updated. ([GitHub][17])\n  * Where available, MAY consider the browser HTML Sanitizer API (note: limited browser availability). ([MDN Web Docs][18])\n* SHOULD pair sanitization with CSP and, where feasible, Trusted Types for defense in depth. ([OWASP Cheat Sheet Series][9])\n\nInsecure patterns:\n\n* Regex-based “strip `<script>`” or “escape `<`” attempts followed by `.html()` insertion.\n* DOMPurify (or similar) configured to allow overly broad tags/attributes, or configuration that’s not reviewed.\n\nDetection hints:\n\n* Search for “sanitize” helper functions, regex replacing `<`/`>` patterns, or “allow all tags” configs.\n* Identify features that render user-generated “rich text” or “custom HTML”.\n* Check if sanitizer results are inserted with `.html()` or equivalent sinks.\n\nFix:\n\n* Introduce a sanitizer with strict allowlist.\n* Centralize the “sanitize then inject” pattern into a single reviewed module.\n* Add regression tests covering representative malicious inputs (don’t store payloads in logs or telemetry).\n\nFalse positive notes:\n\n* If content is guaranteed trusted (e.g., compiled templates shipped by you), document the trust boundary and why it is not attacker-controlled.\n\n---\n\n### JQ-XSS-003: `$(untrustedString)` and `jQuery.parseHTML` MUST NOT process attacker-controlled markup\n\nSeverity: High (if attacker-controlled)\n\nRequired:\n\n* MUST NOT pass attacker-controlled strings to `$()` when they might be interpreted as HTML.\n* MUST treat `jQuery.parseHTML(html, …, keepScripts)` as a high-risk primitive; keepScripts MUST be `false` for any untrusted input. ([jQuery API][2])\n\nInsecure patterns:\n\n* `const $node = $(untrusted);`\n* `$.parseHTML(untrusted, /* context */, true)` (scripts preserved)\n\nDetection hints:\n\n* Search for `$(` calls where the argument is not a static selector or static markup.\n* Search for `$.parseHTML(` and inspect the `keepScripts` argument.\n\nFix:\n\n* Use DOM creation with constant tag names and `.text()` for untrusted values.\n* If parsing HTML is necessary, sanitize first (JQ-XSS-002) and keep scripts disabled.\n\n---\n\n### JQ-XSS-004: `.load()` MUST be treated as an HTML+script injection surface\n\nSeverity: Medium (High if URL/content is attacker-controlled)\n\nRequired:\n\n* MUST NOT use `.load()` with attacker-controlled URLs or attacker-controlled HTML fragments.\n* MUST understand jQuery `.load()` script behavior:\n\n  * Without a selector in the URL, content is passed to `.html()` before scripts are removed, which can execute scripts. ([jQuery API][3])\n* SHOULD prefer `fetch()`/XHR to retrieve data, then render with safe DOM creation or sanitize explicitly.\n\nInsecure patterns:\n\n* `$(\"#target\").load(untrustedUrl)`\n* `$(\"#target\").load(\"/path?param=\" + untrusted)`\n\nDetection hints:\n\n* Search for `.load(` across JS/TS files.\n* Identify whether a selector is appended to the URL (the behavior differs). ([jQuery API][3])\n* Trace whether the URL can be influenced by user input.\n\nFix:\n\n* Replace `.load()` with:\n\n  * `fetch()` to retrieve JSON, then render via `.text()` / node construction, or\n  * `fetch()` to retrieve HTML, sanitize it, then inject.\n* If `.load()` must remain, ensure the URL is constant or strictly allowlisted and the returned content is trusted.\n\n---\n\n### JQ-EXEC-001: Dynamic script execution and script fetching MUST NOT be reachable from untrusted input\n\nSeverity: High\n\nRequired:\n\n* MUST NOT fetch-and-execute scripts from untrusted or user-influenced URLs.\n* MUST treat these as code execution primitives:\n\n  * `$.getScript(url)` executes the fetched script in the global context. ([jQuery API][4])\n  * `$.ajax({ dataType: \"script\" })` and other script-typed requests that execute responses.\n* SHOULD remove these patterns unless there is a strong, reviewed justification.\n\nInsecure patterns:\n\n* `$.getScript(untrustedUrl)`\n* `$.ajax({ url: untrustedUrl, dataType: \"script\" })`\n* Dynamic `<script src=...>` injection where `src` is derived from untrusted input.\n\nDetection hints:\n\n* Search for `getScript(`, `dataType: \"script\"`, `globalEval`, `eval`, `new Function`.\n* Look for “plugin loader” or “theme loader” features that accept URLs.\n\nFix:\n\n* Bundle scripts at build time.\n* If runtime-loading is required, restrict to allowlisted, versioned, integrity-checked assets (and ideally still avoid runtime code loading).\n\n---\n\n### JQ-AJAX-001: JSONP MUST be disabled unless the endpoint is fully trusted (and even then, avoid)\n\nSeverity: Medium (High if attacker can influence URL/endpoint)\n\nRequired:\n\n* MUST NOT use JSONP for untrusted endpoints because it executes JavaScript responses.\n* When using `$.ajax`, MUST explicitly disable JSONP for non-fully-trusted targets; jQuery’s own docs recommend setting `jsonp: false` “for security reasons” if you don’t trust the target. ([jQuery API][5])\n* SHOULD prefer CORS with JSON (`dataType: \"json\"`) and explicit origin allowlists server-side.\n\nInsecure patterns:\n\n* `dataType: \"jsonp\"`\n* URLs containing `callback=?` or patterns that trigger JSONP behavior. callback arguments are historically XSS vectors.\n* `$.get(untrustedUrl)` without pinning `dataType` and disabling JSONP (risk depends on options and jQuery behavior)\n\nDetection hints:\n\n* Search for `jsonp`, `dataType: \"jsonp\"`, `callback=?`.\n* Search for cross-domain AJAX where the URL is not hard-coded or allowlisted.\n\nFix:\n\n* Use JSON over HTTPS with CORS configured server-side.\n* Set:\n\n  * `dataType: \"json\"`\n  * `jsonp: false` (defense in depth when URL might be ambiguous) ([jQuery API][5])\n\n---\n\n### JQ-AJAX-002: State-changing AJAX requests using cookie auth MUST be CSRF-protected\n\nSeverity: High\n\nNOTE: This only matters when using cookie based auth. If the request use Authorization header, there is no CSRF potential.\n\nRequired:\n\n* If authentication uses cookies, MUST protect state-changing requests (POST/PUT/PATCH/DELETE) against CSRF.\n* SHOULD use server-verified CSRF tokens; for AJAX calls, tokens are commonly sent in a custom header. ([OWASP Cheat Sheet Series][19])\n* MUST NOT treat “it’s an AJAX request” as CSRF protection by itself.\n\nInsecure patterns:\n\n* `$.post(\"/transfer\", {...})` or `$.ajax({ method: \"POST\", ... })` with cookie auth and no CSRF token/header.\n* “CSRF protection” that only checks for `X-Requested-With` (defense-in-depth only, not primary).\n\nDetection hints:\n\n* Enumerate state-changing AJAX calls and locate whether they include CSRF tokens.\n* Identify how the server expects CSRF validation (meta tag, cookie-to-header double submit, synchronizer token, etc.).\n\nFix:\n\n* Add CSRF token inclusion in a centralized place, e.g., `$.ajaxSetup({ headers: { \"X-CSRF-Token\": token } })`, and ensure server verifies.\n* Follow OWASP CSRF guidance for token properties and validation. ([OWASP Cheat Sheet Series][19])\n\nFalse positive notes:\n\n* If auth is not cookie-based (e.g., Authorization header bearer token) CSRF risk is different; verify actual auth mechanism.\n\n---\n\n### JQ-ATTR-001: Untrusted values MUST NOT be written into dangerous attributes without validation/allowlisting\n\nSeverity: Low (High for events like onclick)\n\nRequired:\n\n* MUST validate/allowlist URLs written into `href`, `src`, `action`, etc.\n* MUST block dangerous schemes; `javascript:` URLs are discouraged because they can execute code. ([MDN Web Docs][6])\n* MUST NOT set event-handler attributes (`onclick`, `onerror`, etc.) from strings.\n* SHOULD avoid writing untrusted strings into `style` attributes; prefer toggling predefined CSS classes.\n\nInsecure patterns:\n\n* `$(\"a\").attr(\"href\", untrustedUrl)`\n* `$(\"img\").attr(\"src\", untrustedUrl)`\n* `$(el).attr(\"style\", untrustedCss)`\n* `$(el).attr(\"onclick\", untrustedJs)`\n\nDetection hints:\n\n* Search for `.attr(\"href\"`, `.attr(\"src\"`, `.attr(\"style\"`, `.prop(\"href\"`, `.prop(\"src\"`.\n* Trace whether inputs come from URL params, server JSON, DOM, or storage.\n\nFix:\n\n* Parse and validate URLs with `new URL(value, location.origin)` and allowlist protocols (`https:` etc.) and hostnames when needed.\n* For navigation targets, prefer relative paths you construct rather than full URLs.\n* Replace `style` strings with `addClass/removeClass` using predefined class names.\n\n---\n\n### JQ-SELECTOR-001: User-controlled selector fragments MUST be escaped with `jQuery.escapeSelector`\n\nSeverity: Medium (can become High if it enables wrong-element selection in security-relevant UI)\n\nRequired:\n\n* If you must select by an ID/class that can contain special CSS characters, SHOULD use `jQuery.escapeSelector()` (available in jQuery 3.0+). ([jQuery API][20])\n* MUST NOT concatenate raw attacker-controlled strings into selector expressions.\n\nInsecure patterns:\n\n* `$(\"#\" + untrustedId)`\n* `$(\"[data-id='\" + untrusted + \"']\")` (especially without strict quoting/escaping)\n\nDetection hints:\n\n* Search for `\"#\" +`, `\". \" +`, or template strings used inside `$(` selectors.\n* Look for “select by user-supplied id”.\n\nFix:\n\n* `$(\"#\" + $.escapeSelector(untrustedId))` ([jQuery API][20])\n* Prefer stable internal IDs over user-derived selectors.\n\nNotes:\n\n* This is often “robustness”, but it can become security-relevant if incorrect selection causes UI to reveal/modify the wrong data or skip security-related prompts.\n\n---\n\n### JQ-PROTOTYPE-001: Do not deep-merge untrusted objects; prevent prototype pollution\n\nSeverity: Medium\n\nRequired:\n\n* MUST NOT deep-merge (`$.extend(true, …)`) attacker-controlled objects into application objects without filtering dangerous keys.\n* MUST ensure jQuery is >= 3.4.0 to avoid CVE-2019-11358 prototype pollution behavior. ([NVD][13])\n\nInsecure patterns:\n\n* `$.extend(true, target, untrustedObj)`\n* `$.extend(true, {}, defaults, untrustedObj)` where untrustedObj comes from URL/JSON/storage\n\nDetection hints:\n\n* Search for `$.extend(true` and inspect sources of merged objects.\n* Search for “merge options” / “apply config” patterns using untrusted JSON.\n\nFix:\n\n* Prefer:\n\n  * Shallow merges with an allowlisted set of keys, or\n  * A safe merge helper that explicitly rejects `__proto__`, `prototype`, `constructor`, and nested occurrences.\n* Keep jQuery patched.\n\n---\n\n### JQ-CSP-001: CSP and Trusted Types SHOULD be used to make DOM XSS harder to introduce and exploit\n\nSeverity: Medium\n\nRequired:\n\n* SHOULD deploy CSP as defense-in-depth against XSS. ([OWASP Cheat Sheet Series][9])\n* If enabling Trusted Types (`require-trusted-types-for`), MUST ensure DOM injection goes through Trusted Types policies. ([MDN Web Docs][11])\n* When using jQuery 4, SHOULD take advantage of its Trusted Types support (TrustedHTML inputs). ([blog.jquery.com][7])\n\nInsecure patterns:\n\n* “Fixing” a jQuery feature by weakening CSP (`script-src 'unsafe-inline'` / `'unsafe-eval'`) without a compensating plan.\n* No CSP on applications that render user content or manipulate DOM heavily.\n\nDetection hints:\n\n* Look for CSP headers (server configs, framework middleware, meta tags).\n* If not visible in repo, flag as “verify at edge/runtime”.\n\nFix:\n\n* Add CSP incrementally; start by eliminating inline scripts and inline event handlers, then tighten `script-src`.\n* Add Trusted Types where supported and feasible.\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* jQuery version / sourcing:\n\n  * `jquery-*.js` in `vendor/` or `static/`\n  * `package.json` dependency `jquery` pinned to old versions\n  * CDN script tags lacking `integrity`/`crossorigin` ([jquery.com][8])\n* HTML injection sinks (DOM XSS):\n\n  * `.html(`, `.append(`, `.prepend(`, `.before(`, `.after(`, `.replaceWith(`, `.wrap(`\n  * `$(` where argument might be HTML / template strings\n  * `$.parseHTML(` especially with `keepScripts=true` ([jQuery API][2])\n  * `.load(` (and whether selector is appended; script behavior differs) ([jQuery API][3])\n* Script execution / dynamic code:\n\n  * `$.getScript(`, `dataType: \"script\"` ([jQuery API][4])\n  * `dataType: \"jsonp\"` or `jsonp:` usage; `callback=?` patterns ([jQuery API][5])\n  * `eval`, `new Function`, `setTimeout(\"…\")`, `$.globalEval`\n* Dangerous attribute writes:\n\n  * `.attr(\"href\", …)`, `.attr(\"src\", …)`, `.attr(\"style\", …)`\n  * Any assignment of `javascript:`-like schemes or suspicious URL construction ([MDN Web Docs][6])\n* Selector construction:\n\n  * `$(\"#\" + user)` and similar; fix via `$.escapeSelector` ([jQuery API][20])\n* Prototype pollution:\n\n  * `$.extend(true, …, userObj)`; ensure jQuery >= 3.4.0 and filter dangerous keys ([NVD][13])\n* CSRF posture for AJAX:\n\n  * `$.post(` / `$.ajax({ method: ... })` with cookies and no CSRF token/header ([OWASP Cheat Sheet Series][19])\n* Defense-in-depth:\n\n  * Absence of CSP/security headers in configs (or not visible; require runtime verification) ([OWASP Cheat Sheet Series][12])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (HTML insertion / script execution / attribute / selector / object merge)\n* protective controls present (sanitizer, allowlists, CSP, Trusted Types, CSRF validation)\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary jQuery project documentation and release notes:\n\n* jQuery 4.0.0 release notes (Trusted Types/CSP changes; version info): `https://blog.jquery.com/2026/01/17/jquery-4-0-0/`. ([blog.jquery.com][7])\n* Download jQuery (latest version info; CDN + SRI guidance): `https://jquery.com/download/`. ([jquery.com][8])\n* jQuery API: `.html()`: `https://api.jquery.com/html/`. ([jQuery API][21])\n* jQuery API: `.text()`: `https://api.jquery.com/text/`. ([jQuery API][14])\n* jQuery API: `.append()`: `https://api.jquery.com/append/`. ([jQuery API][22])\n* jQuery API: `.load()` (script execution behavior): `https://api.jquery.com/load/`. ([jQuery API][3])\n* jQuery API: `jQuery.parseHTML(…, keepScripts)`: `https://api.jquery.com/jQuery.parseHTML/`. ([jQuery API][2])\n* jQuery API: `$.ajax()` (`jsonp: false` security note): `https://api.jquery.com/jQuery.ajax/`. ([jQuery API][5])\n* jQuery API: `$.getScript()` (executes script): `https://api.jquery.com/jQuery.getScript/`. ([jQuery API][4])\n* jQuery API: `jQuery.escapeSelector()`: `https://api.jquery.com/jQuery.escapeSelector/`. ([jQuery API][20])\n\njQuery vulnerabilities / advisories:\n\n* NVD CVE-2019-11358 (prototype pollution; jQuery < 3.4.0): `https://nvd.nist.gov/vuln/detail/CVE-2019-11358`. ([NVD][13])\n* NVD CVE-2020-11022 (XSS risk in DOM manipulation methods; patched in 3.5.0): `https://nvd.nist.gov/vuln/detail/CVE-2020-11022`. ([NVD][1])\n* NVD CVE-2020-11023 (XSS risk involving `<option>`; patched in 3.5.0): `https://nvd.nist.gov/vuln/detail/CVE-2020-11023`. ([NVD][23])\n* GitHub Security Advisory GHSA-gxr4-xjj5-5px2 (jQuery htmlPrefilter XSS; patched in 3.5.0): `https://github.com/jquery/jquery/security/advisories/GHSA-gxr4-xjj5-5px2`. ([GitHub][16])\n\nOWASP Cheat Sheet Series (web app security foundations relevant to jQuery usage):\n\n* XSS Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html`. ([OWASP Cheat Sheet Series][24])\n* DOM-based XSS Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html`. ([OWASP Cheat Sheet Series][25])\n* CSRF Prevention: `https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html`. ([OWASP Cheat Sheet Series][19])\n* HTTP Security Headers: `https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html`. ([OWASP Cheat Sheet Series][12])\n* Content Security Policy Cheat Sheet: `https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html`. ([OWASP Cheat Sheet Series][9])\n\nBrowser/platform references (SRI, CSP, Trusted Types, and dangerous URL schemes):\n\n* MDN: Subresource Integrity (SRI): `https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity`. ([MDN Web Docs][26])\n* W3C: SRI specification: `https://www.w3.org/TR/sri-2/`. ([W3C][27])\n* MDN: CSP guide: `https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP`. ([MDN Web Docs][28])\n* MDN: `require-trusted-types-for` directive: `https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/require-trusted-types-for`. ([MDN Web Docs][11])\n* MDN: Trusted Types API: `https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API`. ([MDN Web Docs][29])\n* W3C: Trusted Types specification: `https://www.w3.org/TR/trusted-types/`. ([W3C][10])\n* MDN: `javascript:` URL scheme warning: `https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Schemes/javascript`. ([MDN Web Docs][6])\n* DOMPurify project documentation: `https://github.com/cure53/DOMPurify`. ([GitHub][17])\n\n[1]: https://nvd.nist.gov/vuln/detail/cve-2020-11022?utm_source=chatgpt.com \"CVE-2020-11022 Detail - NVD\"\n[2]: https://api.jquery.com/jQuery.parseHTML/?utm_source=chatgpt.com \"jQuery.parseHTML()\"\n[3]: https://api.jquery.com/load/?utm_source=chatgpt.com \".load() | jQuery API Documentation\"\n[4]: https://api.jquery.com/jQuery.getScript/?utm_source=chatgpt.com \"jQuery.getScript()\"\n[5]: https://api.jquery.com/jQuery.ajax/?utm_source=chatgpt.com \"jQuery.ajax()\"\n[6]: https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Schemes/javascript?utm_source=chatgpt.com \"javascript: URLs - URIs - MDN Web Docs\"\n[7]: https://blog.jquery.com/2026/01/17/jquery-4-0-0/ \"jQuery 4.0.0 | Official jQuery Blog\"\n[8]: https://jquery.com/download/ \"Download jQuery | jQuery\"\n[9]: https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html?utm_source=chatgpt.com \"Content Security Policy - OWASP Cheat Sheet Series\"\n[10]: https://www.w3.org/TR/trusted-types/?utm_source=chatgpt.com \"Trusted Types\"\n[11]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/require-trusted-types-for?utm_source=chatgpt.com \"Content-Security-Policy: require-trusted-types-for directive\"\n[12]: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html?utm_source=chatgpt.com \"HTTP Security Response Headers Cheat Sheet\"\n[13]: https://nvd.nist.gov/vuln/detail/cve-2019-11358?utm_source=chatgpt.com \"CVE-2019-11358 Detail - NVD\"\n[14]: https://api.jquery.com/text/?utm_source=chatgpt.com \".text() | jQuery API Documentation\"\n[15]: https://api.jquery.com/val/?utm_source=chatgpt.com \".val() | jQuery API Documentation\"\n[16]: https://github.com/jquery/jquery/security/advisories/GHSA-gxr4-xjj5-5px2 \"Potential XSS vulnerability in jQuery.htmlPrefilter and related methods · Advisory · jquery/jquery · GitHub\"\n[17]: https://github.com/cure53/DOMPurify?utm_source=chatgpt.com \"DOMPurify - a DOM-only, super-fast, uber-tolerant XSS ...\"\n[18]: https://developer.mozilla.org/en-US/docs/Web/API/HTML_Sanitizer_API?utm_source=chatgpt.com \"HTML Sanitizer API - MDN Web Docs\"\n[19]: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html?utm_source=chatgpt.com \"Cross-Site Request Forgery Prevention Cheat Sheet\"\n[20]: https://api.jquery.com/jQuery.escapeSelector/?utm_source=chatgpt.com \"jQuery.escapeSelector()\"\n[21]: https://api.jquery.com/html/?utm_source=chatgpt.com \".html() | jQuery API Documentation\"\n[22]: https://api.jquery.com/append/?utm_source=chatgpt.com \".append() | jQuery API Documentation\"\n[23]: https://nvd.nist.gov/vuln/detail/cve-2020-11023?utm_source=chatgpt.com \"CVE-2020-11023 Detail - NVD\"\n[24]: https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html?utm_source=chatgpt.com \"Cross Site Scripting Prevention - OWASP Cheat Sheet Series\"\n[25]: https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html?utm_source=chatgpt.com \"DOM based XSS Prevention Cheat Sheet\"\n[26]: https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity?utm_source=chatgpt.com \"Subresource Integrity - Security - MDN Web Docs\"\n[27]: https://www.w3.org/TR/sri-2/?utm_source=chatgpt.com \"Subresource Integrity\"\n[28]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP?utm_source=chatgpt.com \"Content Security Policy (CSP) - HTTP - MDN Web Docs\"\n[29]: https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API?utm_source=chatgpt.com \"Trusted Types API - MDN Web Docs\"\n\n<!-- File: core/skills/builtin/security-best-practices/references/javascript-typescript-nextjs-web-server-security.md (Tokens: ~9783 | Category: anthropic-skill) -->\n# Next.js (TypeScript/JavaScript) Web Security Spec (Next.js 16.1.x, Node.js 20.9+)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new Next.js backend code (Route Handlers, API Routes, Server Actions, Proxy/Middleware).\n2. **Security review / vulnerability hunting** in existing Next.js repos (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\nTarget scope: Next.js **16.1.x** (latest line shown in the App Router docs) ([Next.js][1]), running on Node.js **20.9+** (per Next.js system requirements). ([Next.js][2])\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session cookies, OAuth tokens, `process.env` dumps, database URLs with credentials).\n* MUST NOT “fix” security by disabling protections (e.g., disabling origin checks, relaxing CORS to `*`, skipping authz checks, turning off cookie security flags, turning off CSP because it’s “hard”).\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and configuration values that justify each claim.\n* MUST treat uncertainty honestly: if a protection might exist in infrastructure (reverse proxy, CDN, WAF, platform headers), report it as “not visible in app code; verify at runtime/config”.\n* MUST assume all request-facing server code is reachable by attackers unless there is a clearly enforced auth boundary (not just “the UI doesn’t link to it”).\n* MUST treat TypeScript types as **non-security boundaries**: types do not validate runtime input; runtime checks are required. ([Next.js][3])\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new Next.js code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default APIs and proven libraries over custom security code.\n* MUST avoid introducing new risky sinks (dynamic code execution, unsafe redirects, serving user files as HTML, SSRF URL fetchers, building SQL strings, etc.).\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a Next.js repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. Deployment entrypoints and environment (Dockerfiles, `package.json` scripts, hosting config).\n2. Next.js config (`next.config.*`), Proxy/Middleware, routing patterns.\n3. Authentication, sessions, cookies.\n4. CSRF protections and state-changing endpoints (Server Actions, Route Handlers, API Routes).\n5. XSS (React + CSP) and unsafe HTML rendering.\n6. Cache/data-leak hazards (static rendering + caching + “use cache”).\n7. File handling (uploads/downloads) and path traversal.\n8. Injection classes (SQL/ORM misuse, command execution, unsafe deserialization).\n9. Outbound requests (SSRF).\n10. Redirect handling (open redirects).\n11. CORS and security headers.\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nIn Next.js backends, untrusted input includes:\n\nApp Router:\n\n* Route Handler params and request data:\n\n  * `context.params` (dynamic segments), search params (`request.url`, `new URL(request.url).searchParams`)\n  * `request.headers`, `request.cookies`\n  * `await request.json()`, `await request.formData()`, `await request.text()`\n* Dynamic APIs used in Server Components/Server Functions:\n\n  * `headers()` and `cookies()` values ([Next.js][4])\n\nPages Router:\n\n* `req.query`, `req.cookies`, `req.body` in `pages/api/*` handlers ([Next.js][3])\n\nPlus:\n\n* Anything from external systems (webhooks, third-party APIs, message queues)\n* Any persisted user content (DB rows) that originated from users\n\n### 2.2 State-changing request\n\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook send), or initiate privileged actions.\n\nSpecial note for Next.js:\n\n* **Server Actions** are invoked via network requests and can mutate state; treat them as state-changing endpoints. ([Next.js][5])\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + function/route name + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common Next.js backend misconfigurations.\n\n### 3.1 Run Next.js in production mode (MUST)\n\n* MUST run `next build` + `next start` (or the managed platform equivalent), not `next dev`. Dev mode has different error/reporting behavior and is not designed for production exposure. ([Next.js][6])\n* MUST ensure `NODE_ENV=production` in production (Next.js defaults `NODE_ENV` based on command; verify the runtime environment). ([Next.js][7])\n\n### 3.2 Put a reverse proxy / edge layer in front when self-hosting (MUST for public internet)\n\n* If self-hosting, MUST place a reverse proxy (e.g., nginx) or equivalent edge layer in front of the Next.js server to handle malformed requests, slow attacks, payload size limits, rate limiting, and similar concerns. ([Next.js][8])\n\n### 3.3 Baseline header/cookie posture (SHOULD)\n\n* SHOULD set a baseline of security headers globally (CSP, `X-Content-Type-Options`, clickjacking defense via CSP `frame-ancestors` and/or `X-Frame-Options`, etc.). Next.js provides guidance for implementing CSP via Proxy/headers. ([Next.js][7])\n* MUST ensure auth/session cookies use secure attributes (`Secure`, `HttpOnly`, `SameSite`) as appropriate. ([Next.js][9])\nIMPORTANT NOTE: Only set `Secure` in production environment. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n\n### 3.4 Clear separation between server-only and client code (MUST)\n\n* MUST prevent secrets and privileged logic from being bundled into client code.\n* MUST treat `NEXT_PUBLIC_*` environment variables as public (browser-exposed and inlined at build time). ([Next.js][7])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### NEXT-DEPLOY-001: Do not run `next dev` in production; ensure production mode behavior\n\nSeverity: High (if production)\n\nNOTE: If they are deploying to a specific Next.js hosting provider, they do not need to worry about this.\n\nRequired:\n\n* MUST NOT deploy `next dev` or any development server mode to production.\n* MUST ensure production builds and production runtime are used for any public deployment. ([Next.js][6])\n\nInsecure patterns:\n\n* `next dev` in Docker `CMD`, Procfile, platform start command.\n* `NODE_ENV=development` in production environment config.\n* Debug/dev-only endpoints or flags exposed publicly.\n\nDetection hints:\n\n* Search `package.json` scripts and deployment manifests for `next dev`.\n* Search infra for `NODE_ENV=development` or missing `NODE_ENV`.\n* Check Kubernetes/PM2/systemd entrypoints for `next dev`.\n\nFix:\n\n* Use `next build` during CI/build and `next start` at runtime (or platform-native build/run).\n* Ensure environment sets `NODE_ENV=production`.\n\nNote:\n\n* Dev mode is fine for local development. Only flag if it is being used as a production entrypoint.\n\n---\n\n### NEXT-SUPPLY-001: Stay on supported Next.js releases; patch quickly for security advisories\n\nSeverity: High (Critical if known-vulnerable version)\n\nRequired:\n\n* MUST run a supported Next.js version line and apply security updates promptly. Next.js documents an LTS/support policy. ([Next.js][10])\n* MUST treat published advisories as urgent upgrade signals (e.g., update to a patched release). ([GitHub][11])\n\nInsecure patterns:\n\n* Running EOL Next.js major/minor without backported security fixes.\n* Ignoring advisories, or pinning `next` to a vulnerable range.\n\nDetection hints:\n\n* Check `package.json` and lockfiles for `next` version.\n* Compare against Next.js support policy and advisories.\n\nIMPORTANT: Any versions older than these minor versions are vulnerable to \"react2shell\" vulnerability (https://nextjs.org/blog/CVE-2025-66478):\n15.0.5\n15.1.9\n15.2.6\n15.3.6\n15.4.8\n15.5.7\n16.0.7\n\nFix:\n\n* Upgrade `next` to a supported and patched version.\n* Add a dependency update process + CI checks.\n\n\n---\n\n### NEXT-SECRETS-001: Secrets MUST NOT be committed or exposed to the browser\n\nSeverity: High (Critical if secret is client-exposed)\n\nRequired:\n\n* MUST store secrets in environment variables or a secret manager; MUST NOT commit `.env*` files.\n* MUST treat `.env*` as sensitive; Next.js warns you “almost never want to commit these files.” ([Next.js][7])\n* MUST treat any `NEXT_PUBLIC_*` environment variable as public and browser-visible (inlined into the client bundle at build time). ([Next.js][7])\n\nInsecure patterns:\n\n* `.env`, `.env.local`, `.env.production` committed to git.\n* `NEXT_PUBLIC_API_KEY`, `NEXT_PUBLIC_SECRET`, `NEXT_PUBLIC_DATABASE_URL`, etc.\n* Rendering `process.env` values into HTML or returning them from API routes.\n\nDetection hints:\n\n* Scan git history and repo files for `.env` content, `DB_PASS=`, `API_KEY=`, `SECRET=`.\n* Grep for `NEXT_PUBLIC_` and review any sensitive-looking names.\n* Search for `process.env` usage in Client Components (`\"use client\"`) and shared modules.\n\nFix:\n\n* Move secrets to server-only env vars (no `NEXT_PUBLIC_` prefix).\n* Ensure `.env*` is ignored and secrets are injected at deploy time.\n* Rotate leaked keys.\n\n---\n\n### NEXT-SECRETS-002: Avoid server-only → client bundling mistakes (server/client boundary is a security boundary)\n\nSeverity: High\n\nRequired:\n\n* MUST ensure server-only modules (DB clients, secret-dependent code) are not imported into Client Components or other client-bundled code paths.\n* SHOULD use server-only patterns/layers (e.g., a dedicated DAL and server-only modules) and treat boundary violations as security bugs. Next.js explicitly discusses the “server-only” concept for sensitive modules. ([Next.js][6])\n\nInsecure patterns:\n\n* Importing DB clients, admin SDKs, or secret-reading modules into `\"use client\"` components.\n* Shared `lib/` modules imported by both server and client code that reference secrets.\n\nDetection hints:\n\n* Search for `\"use client\"` and examine its imports for server-only dependencies.\n* Look for DB client packages (`pg`, `mysql2`, `mongoose`, `prisma`, admin SDKs) imported from `components/` or other client paths.\n* Search for `process.env` access in UI components.\n\nFix:\n\n* Refactor into `lib/server/*` and only import from server contexts (Route Handlers, Server Components, Server Actions).\n* Add an explicit “server-only” guard pattern (and/or tests) to prevent accidental imports.\n\n---\n\n### NEXT-AUTH-001: Authentication/authorization MUST be enforced server-side for every protected action\n\nSeverity: High\n\nRequired:\n\n* MUST enforce authn/authz in server-side code for:\n\n  * Route Handlers (`app/**/route.ts`) ([Next.js][1])\n  * API Routes (`pages/api/**`) ([Next.js][3])\n  * Server Actions (`\"use server\"` functions invoked by clients) ([Next.js][6])\n* MUST NOT rely on client-side checks (hiding UI, route guards on the client) as the only protection.\n\nInsecure patterns:\n\n* Sensitive Route Handlers with no session verification.\n* Server Actions that mutate data but do not validate user identity/permissions.\n* “Authorization” checks in React components only.\n\nDetection hints:\n\n* Enumerate all Route Handlers and API Routes; for each, identify whether it requires auth.\n* Grep for `\"use server\"` and review all exported actions for auth checks.\n* Search for admin actions triggered by query params / form submits.\n\nFix:\n\n* Centralize auth helpers and call them in every protected endpoint/action.\n* Implement least-privilege authorization checks (role/resource ownership) per action.\n\n---\n\n### NEXT-AUTH-002: Proxy/Middleware-based auth MUST NOT create route coverage gaps\n\nSeverity: High\n\nRequired:\n\n* If using **Proxy** or **Middleware** for authentication checks, MUST ensure it covers every route that needs protection.\n* Next.js documentation notes Proxy can use a `matcher`, and for auth it’s recommended Proxy runs on all routes. ([Next.js][12])\n* MUST treat `matcher` mistakes as an auth bypass risk.\n\nInsecure patterns:\n\n* Proxy/Middleware only matches “pages” but not `/api/*`, or only matches some route groups.\n* “Denylist” style matchers that miss alternative request forms (framework-internal variants, RSC navigations, etc.).\n\nDetection hints:\n\n* Inspect `proxy.ts` / `middleware.ts` and its `matcher`.\n* Compare matchers to the full set of routes (including `app/api/**` and `pages/api/**`).\n* Ensure static assets and Next internals are excluded only intentionally, and that sensitive routes are included.\n\nFix:\n\n* Prefer allowlisting protected route prefixes or running Proxy globally and doing internal allow/deny logic.\n* Add integration tests: request protected route without auth and assert denial.\n\nNotes:\n\n* Proxy is commonly used for “optimistic checks”; it is not a complete authorization system by itself. ([Next.js][12])\n\n---\n\n### NEXT-CSRF-001: Cookie-authenticated state-changing endpoints MUST be CSRF-protected\n\nSeverity: High\n\n- IMPORTANT NOTE: If cookies are not being used for auth (ie auth is via Authentication header or other passed token), then there is no CSRF risk.\n\nRequired:\n\n* MUST protect every state-changing endpoint that relies on cookies for auth (POST/PUT/PATCH/DELETE).\n* For **Server Actions**, Next.js performs an Origin/Host comparison to help prevent CSRF; do not disable or weaken it. ([Next.js][5])\n* If Server Actions must be callable from additional trusted origins (e.g., a trusted proxy domain), MUST use `allowedOrigins` with a strict allowlist. ([Next.js][5])\n* For **Route Handlers** and **API Routes**, MUST implement CSRF protections explicitly (tokens and/or strict Origin/Referer + SameSite + custom headers). Route Handlers are an “escape hatch” and require application-level security decisions. ([Next.js][6])\n\nInsecure patterns:\n\n* POST endpoints (including Server Actions) that mutate state and accept cross-site requests with no token/origin checks.\n* `allowedOrigins: ['*']` (or broad wildcards) or “reflect Origin” logic.\n* Using GET requests to change state.\n\nDetection hints:\n\n* Enumerate all state-changing endpoints and determine auth mechanism.\n* Search for `allowedOrigins` and confirm the list is small, specific, and justified. ([Next.js][5])\n* In Route Handlers/API Routes: look for missing CSRF token validation or missing Origin/Referer checks.\n\nFix:\n\n* Implement a CSRF token strategy for cookie-auth endpoints.\n* Keep cookies `SameSite=Lax` or `Strict` when compatible; don’t treat SameSite alone as sufficient.\n* Use strict Origin validation for JSON API endpoints, especially when not using CSRF tokens.\n\nNotes:\n\n* XSS can defeat CSRF protections; CSRF defenses do not replace XSS prevention.\n\n---\n\n### NEXT-SESS-001: Session cookies MUST use secure attributes in production\n\nSeverity: Medium\n\nRequired (production, HTTPS):\n\n* MUST set session/auth cookies with:\n\n  * `Secure: true` (HTTPS-only) IMPORTANT NOTE: Only set `Secure` in production environment. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n  * `HttpOnly: true` (not readable by JS)\n  * `SameSite: 'Lax'` (recommended) or `'Strict'` if compatible\n* Only use `SameSite: 'none'` when you truly need cross-site cookies, and then MUST also set `Secure`. Cookie options are supported in Next.js cookie APIs. ([Next.js][9])\n\nInsecure patterns:\n\n* `secure: false` in production.\n* `httpOnly: false` for auth cookies.\n* `sameSite: 'none'` without a clear need, especially on cookie-authenticated state-changing endpoints.\n\nDetection hints:\n\n* Search for cookie setting sites (`cookies().set(...)`, `Set-Cookie` headers, auth library cookie config).\n* Review cookie options used in Route Handlers and Server Actions. ([Next.js][9])\n\nFix:\n\n* Set secure cookie attributes at the auth/session layer.\n* Reduce cookie scope: avoid wide `domain` unless you explicitly need subdomain-wide cookies.\n\n---\n\n### NEXT-SESS-002: Sessions MUST be bounded and resistant to fixation/replay\n\nSeverity: Low\n\nRequired:\n\n* SHOULD set bounded session lifetimes appropriate to the app.\n* SHOULD rotate session identifiers on login and privilege changes.\n* MUST NOT store sensitive secrets directly in client-readable storage (including cookies that are not encrypted).\n\nInsecure patterns:\n\n* Long-lived admin sessions with no rotation.\n* “Remember me forever” for privileged roles without additional risk controls.\n* Storing access tokens/refresh tokens in non-HttpOnly cookies or localStorage.\n\nDetection hints:\n\n* Review auth library configuration for expiration and rotation.\n* Search for `localStorage.setItem('token'...)` and non-HttpOnly cookie usage.\n\nFix:\n\n* Use short lifetimes for privileged sessions; refresh with rotation.\n* Store only opaque session IDs in cookies; keep sensitive material server-side.\n\n---\n\n### NEXT-INPUT-001: Runtime input validation is mandatory (TypeScript is not validation)\n\nSeverity: High\n\nRequired:\n\n* MUST validate and normalize all attacker-controlled input at runtime (schemas, type checks, bounds).\n* Next.js API Routes explicitly note `req.body` is `any` and must be validated before use. ([Next.js][3])\n* MUST validate Server Action arguments (treat as hostile). ([Next.js][6])\n\nInsecure patterns:\n\n* Trusting `req.body` shape directly.\n* Passing `params.id`/`searchParams` directly into DB queries or file paths.\n* Parsing JSON and then assuming types without validation.\n\nDetection hints:\n\n* Identify endpoints that accept JSON/form input and check for schema validation.\n* Grep for `req.body.` usage and for `await request.json()` usage in Route Handlers; verify validation exists.\n\nFix:\n\n* Add schema validation (e.g., zod/yup/valibot) and reject invalid input with 4xx.\n* Validate IDs as strict types (UUID/int) and enforce length/charset constraints.\n\n---\n\n### NEXT-HEADERS-001: Essential security headers MUST be set (in app or at the edge)\n\nSeverity: Low\n\nRequired (typical web app):\n\n* SHOULD set:\n\n  * CSP (`Content-Security-Policy`) (see NEXT-CSP-001)\n  * `X-Content-Type-Options: nosniff`\n  * Clickjacking defense (`frame-ancestors` in CSP and/or `X-Frame-Options`)\n  * `Referrer-Policy` and `Permissions-Policy` when appropriate\n* MUST ensure cookies are set with secure attributes (see NEXT-SESS-001). ([Next.js][9])\n\nInsecure patterns:\n\n* No security headers anywhere (app or edge).\n* Allowing iframing unintentionally.\n* `Content-Type` sniffing possible due to missing `nosniff`.\n\nDetection hints:\n\n* Check `proxy.ts` / middleware for `response.headers.set(...)`. ([Next.js][7])\n* If not visible in app code, flag as “verify at edge/CDN”.\n\nFix:\n\n* Set headers centrally (Proxy/Middleware or other centralized mechanism).\n* Ensure consistent headers across routes.\n\n---\n\n### NEXT-CSP-001: Use a CSP to reduce XSS impact; prefer nonces for scripts\n\nSeverity: Medium\n\nNOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n\nRequired:\n\n* SHOULD deploy a CSP, ideally with nonces for scripts.\n* SHOULD follow Next.js guidance for CSP implementation (including nonce generation and header application). ([Next.js][7])\n* MUST avoid loosening CSP as a “fix” (e.g., `script-src 'unsafe-inline'`) without explicit risk acceptance.\n\nInsecure patterns:\n\n* CSP missing on apps that display user-generated HTML/markdown.\n* CSP that broadly enables inline scripts or eval without strict justification.\n\nDetection hints:\n\n* Search for `Content-Security-Policy` header setting and examine its directives.\n* Check use of `next/script` and whether a nonce is provided when CSP requires it.\n\nFix:\n\n* Implement CSP per Next.js guidance; use a nonce and apply it consistently.\n* Reduce inline scripts; avoid `eval`.\n\nNotes:\n\n* CSP is defense-in-depth; it does not replace proper output encoding and sanitization.\n\n---\n\n### NEXT-XSS-001: Prevent reflected/stored XSS in React/Next rendering\n\nSeverity: High\n\nRequired:\n\n* MUST rely on React’s default escaping; MUST NOT insert untrusted HTML into the DOM without sanitization.\n* MUST treat these as high-risk sinks:\n\n  * `dangerouslySetInnerHTML`\n  * rendering user-controlled strings into `<script>` tags or event handler attributes\n* MUST avoid serving uploaded HTML as active HTML (serve as attachment or sanitize/transform).\n\nInsecure patterns:\n\n* `<div dangerouslySetInnerHTML={{ __html: userContent }} />` with no sanitizer.\n* Markdown renderers configured to allow raw HTML with no sanitizer.\n* Returning user content with `Content-Type: text/html` from a Route Handler.\n\nDetection hints:\n\n* Search for `dangerouslySetInnerHTML`, `__html:`.\n* Search for template-like string concatenation that builds HTML.\n* Review any “render HTML” or “preview” features.\n\nFix:\n\n* Sanitize untrusted HTML with a well-maintained sanitizer; prefer strict allowlists.\n* Prefer rendering user content as text, not HTML.\n* Add CSP to reduce impact.\n\n---\n\n### NEXT-ACTION-001: Server Actions MUST be treated like public endpoints\n\nSeverity: High (Critical for privileged actions)\n\nRequired:\n\n* MUST apply the same controls as for Route Handlers:\n\n  * authn/authz\n  * input validation\n  * CSRF/origin protections\n  * rate limiting for sensitive actions\n* MUST NOT assume Server Actions are “not reachable” or “internal”.\n* MUST understand Server Action request protections:\n\n  * Next.js compares Origin with host to mitigate CSRF; extra origins must be explicitly allowlisted via `allowedOrigins`. ([Next.js][5])\n\nInsecure patterns:\n\n* `\"use server\"` functions that update DB state with no auth check.\n* Adding overly broad `allowedOrigins` to “make it work”.\n\nDetection hints:\n\n* Grep for `\"use server\"` and inventory all exported actions.\n* Identify any action doing privileged writes; confirm it checks identity and permission.\n\nFix:\n\n* Wrap actions with an authz helper (fail closed).\n* Keep `allowedOrigins` minimal and audited.\n\n---\n\n### NEXT-ACTION-002: Do not accidentally leak secrets through Server Action closure/binding patterns\n\nSeverity: Medium (High if important secrets are exposed)\n\nRequired:\n\n* MUST treat Server Action closed-over values as sensitive and design intentionally.\n* Next.js notes that closed-over values are encrypted/signed, but values passed through `.bind` are not encrypted; do not rely on `.bind` to protect secrets. ([Next.js][6])\n* If using a stable encryption key for Server Actions across deployments, MUST treat it as a secret and store securely (do not commit/log it). ([Next.js][6])\n\nInsecure patterns:\n\n* `myAction.bind(null, process.env.SECRET)` or binding sensitive tokens/IDs that should not be client-influenced.\n* Logging action arguments that include secrets.\n\nDetection hints:\n\n* Search for `.bind(` on Server Action functions.\n* Search for `process.env` usage near Server Actions.\n\nFix:\n\n* Avoid binding secrets into actions; fetch secrets server-side inside the action.\n* Keep action arguments minimal and validated.\n\n---\n\n### NEXT-CACHE-001: Prevent data leaks via static rendering and shared caching\n\nSeverity: High (Critical if cross-user data leak)\n\nRequired:\n\n* MUST ensure pages/endpoints that return user-specific or sensitive data are not statically generated or cached in a shared way.\n* Route Handlers are not cached by default, but GET handlers can opt into caching/static behavior; do not do this for per-user data. ([Next.js][1])\n* MUST treat `use cache` and similar caching mechanisms as potentially cross-user unless explicitly proven private; do not cache per-user DB results in shared caches. ([Next.js][1])\n* SHOULD set explicit `Cache-Control: no-store` / `private` for sensitive responses (auth/session/user data APIs).\n\nInsecure patterns:\n\n* `export const dynamic = 'force-static'` on a route that returns user-specific data. ([Next.js][1])\n* Using `use cache` around a function that queries user-specific data without a per-user cache key. ([Next.js][1])\n* Returning auth/session responses from GET endpoints with caching enabled.\n\nDetection hints:\n\n* Search for `dynamic = 'force-static'`, `revalidate`, `use cache`, `cacheLife`, `unstable_cache`.\n* Inspect all GET Route Handlers that are cached/static and confirm they only return public data.\n* Confirm that use of `cookies()`/`headers()` (dynamic APIs) is not accidentally removed in ways that make a route static. ([Next.js][1])\n\nFix:\n\n* Mark sensitive routes as dynamic and set `Cache-Control: no-store`.\n* Ensure caching keys include user identity if caching is truly needed (and store it in a user-private cache).\n\n---\n\n### NEXT-FILES-001: User uploads MUST be validated, stored safely, and served safely\n\nSeverity: Medium\n\nRequired:\n\n* MUST enforce upload size limits at the edge and in application logic.\n* MUST validate file type using allowlists and content checks (not only extension).\n* MUST store uploads outside the `public/` directory (anything under `public/` is served as static content by default).\n* MUST serve potentially active formats safely (`Content-Disposition: attachment`) unless explicitly intended.\n\nInsecure patterns:\n\n* Accepting arbitrary file types and serving them back inline.\n* Using user-supplied filename as the storage path.\n* Writing uploads into `public/uploads/` and serving them directly.\n\nDetection hints:\n\n* Search for `formData()` / multipart parsing, `fs.writeFile`, storage SDK usage.\n* Look for any write path under `public/`.\n* Look for “download” endpoints that set `Content-Type: text/html` or serve user files inline.\n\nFix:\n\n* Use a dedicated object store (S3/GCS) or a safe server-side directory outside static roots.\n* Generate random server-side filenames; store metadata separately.\n\n---\n\n### NEXT-PATH-001: Prevent path traversal and unsafe file access\n\nSeverity: High\n\nRequired:\n\n* MUST NOT use user-controlled strings as filesystem paths.\n* MUST validate and normalize identifiers; use allowlists and safe base directories.\n* MUST avoid reading arbitrary files based on request parameters.\n\nInsecure patterns:\n\n* `fs.readFile(request.nextUrl.searchParams.get('path'))`\n* `path.join(base, userPath)` without normalization + boundary checks\n\nDetection hints:\n\n* Search for `fs.` usage in Route Handlers/API Routes.\n* Search for `path.join`/`path.resolve` fed by request params.\n\nFix:\n\n* Use opaque IDs that map to server-side stored paths.\n* Enforce that resolved paths remain within an intended base directory.\n* Sanitize and disallow `..` from being used when creating urls\n\n---\n\n### NEXT-SSRF-001: Outbound requests using user-influenced URLs MUST be restricted\n\nSeverity: Medium (High in internal networks)\n\nNOTE: This is mostly only applicable to apps which will be deployed in a cloud/LAN setup or have other http services on the same box. Sometimes the feature requires this functionality unavoidably (webhooks).\n\nRequired:\n\n* MUST treat any server-side `fetch()` to a user-provided URL as high-risk.\n* SHOULD allowlist destinations (hosts/domains) for URL fetch features.\n* SHOULD block:\n\n  * localhost / private IP ranges / link-local\n  * cloud metadata endpoints\n* MUST restrict protocols to `http:` and `https:`.\n* SHOULD set strict timeouts and restrict redirects.\n\nInsecure patterns:\n\n* `await fetch(req.query.url)` or `await fetch((await request.json()).url)`\n* “URL preview” endpoints that fetch arbitrary URLs.\n\nDetection hints:\n\n* Search for `fetch(` in server code and trace where the URL comes from.\n* Look for “webhook tester”, “preview”, “import from URL” features.\n\nFix:\n\n* Parse URL, enforce `http/https`, allowlist hostnames, re-resolve DNS/IP to block private ranges.\n* Set timeouts (AbortSignal) and limit redirects.\n\n---\n\n### NEXT-REDIRECT-001: Prevent open redirects (including auth flows)\n\nSeverity: Low\n\nRequired:\n\n* MUST validate redirect targets derived from untrusted input (e.g., `next`, `redirect`, `returnTo`).\n* SHOULD prefer redirecting only to same-site relative paths.\n* MUST validate any absolute URL against an allowlist.\n* MUST ensure urls are `http` or `https:` schema, disallowing `javascript:` schema\n\nInsecure patterns:\n\n* `redirect(searchParams.get('next')!)`\n* `NextResponse.redirect(new URL(req.nextUrl.searchParams.get('to')!, req.url))` without checks\n\nDetection hints:\n\n* Search for `redirect(` (server components/actions) and `NextResponse.redirect`.\n* Search for `res.redirect(` in API Routes. ([Next.js][3])\n\nFix:\n\n* Only allow relative paths (`/path`) and reject protocol-relative (`//evil.com`) or absolute URLs.\n* If invalid, fall back to a safe default (home/dashboard).\n\n---\n\n### NEXT-CORS-001: CORS must be explicit and least-privilege\n\nSeverity: Medium (High if misconfigured with credentials)\n\nRequired:\n\n* If CORS is not needed, MUST keep it disabled.\n* Next.js API Routes do not set CORS headers by default, meaning they are same-origin by default; only enable CORS when you truly need it. ([Next.js][3])\n* If enabling CORS:\n\n  * MUST allowlist trusted origins (no reflection of arbitrary Origin)\n  * MUST be careful with credentialed requests (cookies); never combine broad origins with credentials.\n  * SHOULD restrict methods and headers.\n\nInsecure patterns:\n\n* `Access-Control-Allow-Origin: *` with `Access-Control-Allow-Credentials: true`\n* Reflecting `Origin` without validation.\n\nDetection hints:\n\n* Search for `Access-Control-Allow-Origin`, `cors`, “CORS” middleware/wrappers.\n* Review preflight `OPTIONS` handlers.\n\nFix:\n\n* Implement strict origin allowlist and minimal methods/headers.\n* Ensure cookies aren’t exposed cross-origin unless necessary and reviewed.\n\n---\n\n### NEXT-WEBHOOK-001: Webhook endpoints MUST verify authenticity using the raw body\n\nSeverity: Medium\n\nRequired:\n\n* MUST verify webhook signatures using the **raw request body** (not a re-serialized parsed object).\n* Next.js notes a use case for disabling body parsing is verifying the raw body of a webhook request. ([Next.js][3])\n\nInsecure patterns:\n\n* Verifying webhook signatures over `JSON.stringify(req.body)` (can change formatting).\n* Accepting webhooks with no signature verification and no allowlist.\n\nDetection hints:\n\n* Find webhook endpoints (`/api/webhook`, `/app/api/**/webhook`).\n* Check whether they use raw body verification.\n\nFix:\n\n* Disable Next.js automatic body parsing only for those webhook routes, read raw bytes safely, verify signature, then parse.\n\n---\n\n### NEXT-INJECT-001: Prevent SQL injection (use parameterized queries / ORM)\n\nSeverity: High\n\nRequired:\n\n* MUST use parameterized queries or an ORM that parameterizes under the hood.\n* MUST NOT build SQL by string concatenation / template strings with untrusted input.\n\nInsecure patterns:\n\n* ``db.query(`SELECT * FROM users WHERE id = ${id}`)``\n* `\"WHERE name = '\" + user + \"'\"`\n\nDetection hints:\n\n* Grep for `SELECT`, `INSERT`, `UPDATE`, `DELETE` strings.\n* Trace untrusted input (`params`, `searchParams`, `req.query`, `req.body`, `request.json()`) into DB calls.\n\nFix:\n\n* Use prepared statements / ORM query APIs.\n* Validate and coerce types before querying.\n\n---\n\n### NEXT-INJECT-002: Prevent OS command injection and unsafe subprocess use\n\nSeverity: Critical to High\n\nRequired:\n\n* MUST avoid executing OS commands with attacker-controlled input.\n* If subprocess is necessary:\n\n  * MUST pass args as an array (not a single shell string)\n  * MUST NOT use `shell: true` with attacker-influenced strings\n  * SHOULD use strict allowlists for any variable component\n\nInsecure patterns:\n\n* `exec(\"convert \" + filename)`\n* `spawn(\"bash\", [\"-c\", userInput])`\n* `spawn(userInput, [\"foo\"])`\n\nDetection hints:\n\n* Search for `child_process`, `exec`, `spawn`, `shell: true`.\n\nFix:\n\n* Use library APIs instead of shell commands.\n* Hard-code commands and allowlist validated parameters (and use `--` to separate flags where supported).\n\n---\n\n### NEXT-INJECT-003: Avoid dynamic code execution and unsafe deserialization\n\nSeverity: High to Critical\n\nRequired:\n\n* MUST NOT use `eval`, `new Function`, `vm.runIn*` on untrusted strings.\n* MUST treat deserializing complex formats (YAML, XML, custom serialization) as risky; use safe parsers and strict schemas.\n\nInsecure patterns:\n\n* `eval(req.body.code)`\n* Parsing YAML from user input with a non-safe schema.\n\nDetection hints:\n\n* Search for `eval(`, `new Function`, `vm.`, `require(` with non-literals.\n* Search for `js-yaml`, XML parsers, custom serializer usage on untrusted input.\n\nFix:\n\n* Remove dynamic execution; use safe interpreters or strict parsers.\n* Validate and constrain input.\n\n---\n\n### NEXT-LOG-001: Logging MUST NOT leak secrets or sensitive headers\n\nSeverity: Medium\n\nRequired:\n\n* MUST NOT log:\n\n  * `Authorization` headers\n  * cookies / session tokens\n  * request bodies containing credentials\n  * environment variables or configuration dumps\n* SHOULD implement structured logging with redaction.\n\nInsecure patterns:\n\n* `console.log(req.headers)` in auth endpoints\n* `console.log(process.env)` in server code\n\nDetection hints:\n\n* Search for `console.log(`, `logger.info(`, `debug(` in server routes/actions.\n* Check for logs of headers/cookies/body.\n\nFix:\n\n* Redact sensitive fields; log only what is needed for debugging.\n* Use safe error messages for clients; keep detail server-side only.\n\n---\n\n### NEXT-ERROR-001: Error handling MUST avoid leaking implementation details in production\n\nSeverity: Low\n\nRequired:\n\n* MUST not expose stack traces or internal error details to end users in production.\n* Ensure production mode behavior (Next.js production error handling differs from dev). ([Next.js][6])\n\nInsecure patterns:\n\n* Returning `err.stack` in JSON responses.\n* Showing detailed exception data to unauthenticated users.\n\nDetection hints:\n\n* Search for `res.status(500).json(err)` or `return Response.json(err)`.\n* Verify error responses are sanitized.\n\nFix:\n\n* Return generic error messages to clients; log details server-side with redaction.\n\n---\n\n### NEXT-PROXY-001: Proxy/Middleware must not introduce header smuggling or unsafe header forwarding\n\nSeverity: Medium\n\nRequired:\n\n* MUST be careful when copying/forwarding request headers upstream:\n\n  * Do not forward attacker-controlled `x-forwarded-*` headers unless you have a trusted proxy chain.\n  * Do not forward `Authorization`/cookies to unrelated outbound services.\n* Next.js Proxy patterns often mutate headers; ensure this doesn’t create security issues.\n\nInsecure patterns:\n\n* Blindly cloning all request headers to an outbound `fetch()` call.\n* Trusting `x-forwarded-host` or `host` to construct sensitive absolute URLs without allowlisting.\n\nDetection hints:\n\n* Search `headers()` and `request.headers` usage (especially for URL building). ([Next.js][4])\n* Search Proxy/Middleware for header rewrites.\n\nFix:\n\n* Allowlist forwarded headers explicitly.\n* Validate hostnames before using them to build callback URLs or redirects.\n\n---\n\n### NEXT-HOST-001: Host/Origin-derived URL construction MUST be allowlisted\n\nSeverity: Medium\n\nRequired:\n\n* MUST NOT generate security-sensitive absolute URLs (password reset links, OAuth callback URLs, email verification links) directly from unvalidated `Host` headers.\n* For Server Actions, Origin/Host matching is part of CSRF mitigation; do not weaken it. ([Next.js][5])\n\nInsecure patterns:\n\n* `const base = \"https://\" + request.headers.get(\"host\")`\n* Using unvalidated `x-forwarded-host` for absolute URL generation.\n\nDetection hints:\n\n* Grep for `.get('host')`, `.get('x-forwarded-host')`, and absolute URL building.\n* Review auth-related email link generation code.\n\nFix:\n\n* Use a configured, allowlisted canonical app origin (e.g., `APP_ORIGIN=https://example.com`).\n* Allowlist hostnames; fail closed.\n\n---\n\n### NEXT-DOS-001: Rate limiting and resource controls MUST exist for abuse-prone endpoints\n\nSeverity: Medium\n\nRequired:\n\n* SHOULD implement rate limiting/throttling for:\n\n  * login, password reset, signup\n  * expensive Server Actions\n  * webhook ingestion\n* MUST implement request size limits (see NEXT-LIMITS-001).\n* If self-hosting, MUST rely on reverse proxy for additional protections. ([Next.js][8])\n\nInsecure patterns:\n\n* No throttling on login/reset endpoints.\n* Expensive actions callable without auth or with unlimited frequency.\n\nDetection hints:\n\n* Identify auth endpoints and check for rate limiting.\n* Search for “send email”, “charge”, “generate report” flows.\n\nFix:\n\n* Add edge rate limiting and app-level user/IP throttles.\n* Add job queues for heavy work; return 202 when appropriate.\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* Production misconfig:\n\n  * `next dev`, `NODE_ENV=development`, dev-only start commands ([Next.js][7])\n* Secrets exposure:\n\n  * `.env` committed, `NEXT_PUBLIC_` on sensitive variables ([Next.js][7])\n  * `process.env` used in `\"use client\"` modules\n* Auth coverage:\n\n  * `app/**/route.ts` or `pages/api/**` with no auth checks ([Next.js][1])\n  * `\"use server\"` actions with DB writes and no authz ([Next.js][6])\n  * `proxy.ts` / `middleware.ts` matchers that exclude sensitive routes ([Next.js][12])\n* CSRF:\n\n  * cookie-auth POST/PUT/PATCH/DELETE with no token/origin checks\n  * `serverActions.allowedOrigins` too broad ([Next.js][5])\n* XSS:\n\n  * `dangerouslySetInnerHTML`, raw HTML markdown rendering\n  * missing CSP / overly permissive CSP ([Next.js][7])\n* Caching/data leak:\n\n  * `dynamic = 'force-static'` on sensitive GET handlers ([Next.js][1])\n  * `use cache`, `cacheLife`, `unstable_cache` around user-specific data ([Next.js][1])\n* Files:\n\n  * writing uploads under `public/`\n  * `fs.readFile` / `path.join` with request input\n* SSRF:\n\n  * `fetch(userProvidedUrl)` from Route Handlers / Server Actions\n* Redirect:\n\n  * `redirect(searchParams.get('next'))`, `NextResponse.redirect(...)`, `res.redirect(req.query.next)` ([Next.js][3])\n* CORS:\n\n  * wildcard origins, origin reflection, credentials + broad origins ([Next.js][3])\n* Limits:\n\n  * API routes with `bodyParser: false` and no raw-body verification for webhooks ([Next.js][3])\n  * `serverActions.bodySizeLimit` raised without justification ([Next.js][5])\n* Dependency hygiene:\n\n  * old `next` versions that conflict with support policy/advisories ([Next.js][10])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (HTML/DOM, SQL, subprocess, files, redirect, outbound HTTP)\n* protective controls present (schema validation, allowlists, middleware/proxy checks, authz helpers, edge protections)\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary framework documentation (Next.js):\n\n* Next.js Docs: Installation (system requirements / Node version) — `https://nextjs.org/docs/app/getting-started/installation`\n* Next.js Docs: Route Handlers — `https://nextjs.org/docs/app/getting-started/route-handlers`\n* Next.js Docs: API Routes (Pages Router) — `https://nextjs.org/docs/pages/building-your-application/routing/api-routes`\n* Next.js Docs: Environment Variables — `https://nextjs.org/docs/pages/guides/environment-variables`\n* Next.js Docs: Data Security — `https://nextjs.org/docs/app/guides/data-security`\n* Next.js Docs: Content Security Policy — `https://nextjs.org/docs/app/guides/content-security-policy`\n* Next.js Docs: Proxy — `https://nextjs.org/docs/app/getting-started/proxy`\n* Next.js Docs: `serverActions.allowedOrigins` and `serverActions.bodySizeLimit` — `https://nextjs.org/docs/app/api-reference/config/next-config-js/serverActions`\n* Next.js Docs: `cookies()` — `https://nextjs.org/docs/app/api-reference/functions/cookies`\n* Next.js Docs: `headers()` — `https://nextjs.org/docs/app/api-reference/functions/headers`\n* Next.js Docs: Self-hosting (reverse proxy guidance) — `https://nextjs.org/docs/pages/guides/self-hosting`\n* Next.js Docs: Support policy (supported versions/LTS) — `https://nextjs.org/docs/support-policy`\n\nNext.js security guidance & advisories:\n\n* Next.js Blog: How to think about security in Next.js — `https://nextjs.org/blog/security-nextjs-server-components-actions`\n* GitHub Security Advisory: Next.js DoS via Server Components / Server Actions (CVE-2026-23864) — `https://github.com/advisories/GHSA-fq29-rrrv-cq2m`\n* Next.js Blog: Security update (example security advisory context) — `https://nextjs.org/blog/security-update`\n\nGeneral web security references (recommended baseline):\n\n* OWASP Cheat Sheet Series (CSRF, Session Management, XSS Prevention, SSRF Prevention, File Upload, HTTP Headers) — `https://cheatsheetseries.owasp.org/`\n\n[1]: https://nextjs.org/docs/app/getting-started/route-handlers \"Getting Started: Route Handlers | Next.js\"\n[2]: https://nextjs.org/docs/app/getting-started/deploying?utm_source=chatgpt.com \"Getting Started: Deploying\"\n[3]: https://nextjs.org/docs/pages/building-your-application/routing/api-routes \"Routing: API Routes | Next.js\"\n[4]: https://nextjs.org/docs/app/api-reference/functions/headers \"Functions: headers | Next.js\"\n[5]: https://nextjs.org/docs/app/api-reference/config/next-config-js/serverActions \"next.config.js: serverActions | Next.js\"\n[6]: https://nextjs.org/blog/security-nextjs-server-components-actions \"How to Think About Security in Next.js | Next.js\"\n[7]: https://nextjs.org/docs/pages/guides/environment-variables \"Guides: Environment Variables | Next.js\"\n[8]: https://nextjs.org/docs/pages/guides/self-hosting?utm_source=chatgpt.com \"Guides: Self-Hosting\"\n[9]: https://nextjs.org/docs/app/api-reference/functions/cookies \"Functions: cookies | Next.js\"\n[10]: https://nextjs.org/blog/next-16?utm_source=chatgpt.com \"Next.js 16\"\n[11]: https://github.com/vercel/next.js/security/advisories/GHSA-9g9p-9gw9-jx7f?utm_source=chatgpt.com \"Denial of Service in Image Optimizer · Advisory\"\n[12]: https://nextjs.org/docs/pages/guides/authentication \"Guides: Authentication | Next.js\"\n\n<!-- File: core/skills/builtin/security-best-practices/references/javascript-typescript-react-web-frontend-security.md (Tokens: ~9638 | Category: anthropic-skill) -->\n# React (JavaScript/TypeScript) Web Security Spec (React 19.x, TypeScript 5.x)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new React code.\n2. **Security review / vulnerability hunting** in existing React code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, OAuth client secrets, private keys, session cookies, JWTs, signing keys).\n\n  * Frontend note: anything shipped to the browser is observable by end users and attackers (view-source, devtools, proxies); never treat client code or “env vars in the bundle” as secret. ([create-react-app.dev][1])\n* MUST NOT “fix” security by disabling protections (e.g., turning off CSP to “make it work”, adding `unsafe-inline`/`unsafe-eval` without a documented, constrained plan, disabling CSRF protections when using cookies, widening CORS, skipping sanitization, or “temporary” bypasses that ship). ([OWASP Cheat Sheet Series][2])\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and configuration values that justify the claim.\n* MUST treat uncertainty honestly: if a protection might exist in infra (CDN/WAF/reverse proxy), report it as “not visible in app code; verify via runtime headers / edge config”.\n* MUST assume any data that crosses a trust boundary (URL, storage, network, postMessage, third-party scripts) can be attacker-influenced unless proven otherwise (see §2.1).\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new React code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default APIs and proven libraries over custom security code.\n* MUST avoid introducing new risky sinks (raw HTML insertion, direct DOM sinks like `innerHTML`, dynamic code execution, untrusted redirects/navigation, third‑party script injection, unsafe token storage, etc.). ([MDN Web Docs][3])\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a React repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. App entrypoints, build tooling (Vite/Webpack/CRA/Next), deployment configs, CDN/static hosting config.\n2. Secrets & configuration exposure (env vars, runtime config injection, source maps).\n3. Rendering of untrusted data (XSS/DOM XSS), especially `dangerouslySetInnerHTML`, markdown/HTML renderers, URL attributes.\n4. Direct DOM usage and dangerous JS execution (`innerHTML`, `eval`, `new Function`, `document.write`, etc.).\n5. Auth & session patterns (token storage, cookies, CSRF interactions, OAuth flows).\n6. Network layer (axios/fetch wrappers, dynamic base URLs, credentialed requests, data exfil risks).\n7. Navigation & redirect handling (open redirects, `window.location`, `target=_blank`, `window.open`).\n8. Third-party scripts/tags/analytics and integrity controls (CSP, SRI).\n9. Service worker/PWA behavior (HTTPS, caching rules, update strategy).\n10. Security headers posture (CSP, clickjacking, nosniff, referrer policy) in app or at the edge. ([OWASP Cheat Sheet Series][2])\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nExamples include:\n\n* URL-derived data: `window.location`, query params, hash fragments, route params.\n* Any data from browser storage: `localStorage`, `sessionStorage`, `IndexedDB` (including data previously written by the app—because XSS or extensions can tamper with it). ([OWASP Cheat Sheet Series][4])\n* Any data from cross-window messaging: `window.postMessage` payloads. ([OWASP Cheat Sheet Series][4])\n* Any data from remote APIs, webhooks proxied to the client, GraphQL responses, CMS content, feature flag services.\n* Any persisted user content (profiles, comments, rich text, markdown) rendered in the UI.\n* Any data produced by third-party scripts or tag managers (treat as untrusted unless strongly controlled). ([OWASP Cheat Sheet Series][5])\n\n### 2.2 State-changing request (frontend perspective)\n\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook), or initiate privileged actions.\n\nFrontend-specific note:\n\n* State changes are often triggered by `fetch/axios` calls or form submissions. If authentication is cookie-based, these calls can be CSRF-relevant (§4 REACT-CSRF-001). ([OWASP Cheat Sheet Series][6])\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + component/function + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common React frontend misconfigurations.\n\n### 3.1 Production build and configuration hygiene (MUST)\n\n* MUST ship a production build (minified, no dev-only overlays/tools, correct mode flags).\n* MUST ensure build-time configuration does not embed secrets into the shipped JS/HTML/CSS. Build-time “environment variables” are not secret; treat them as public. ([create-react-app.dev][1])\n* SHOULD treat source maps as sensitive operational artifacts:\n\n  * Either don’t publish them publicly, or publish them only where intended (e.g., behind auth or to an error-reporting provider), because they can reveal code structure and internal URLs.\n\n### 3.2 Browser-enforced protections (SHOULD, but baseline expectation for modern apps)\n\n* SHOULD deploy a CSP as defense-in-depth against XSS, and keep it compatible with your React build (avoid `unsafe-inline` and `unsafe-eval` unless strictly necessary and documented). ([OWASP Cheat Sheet Series][2])\n* SHOULD use Subresource Integrity (SRI) for any third-party script/style loaded from a CDN (or self-host instead). ([MDN Web Docs][7])\n* SHOULD enable clickjacking defenses via `frame-ancestors` (CSP) and/or `X-Frame-Options`, unless embedding is an explicit product requirement. ([MDN Web Docs][8])\n\n### 3.3 High-risk features baseline (MUST if used)\n\n* If rendering any user-provided HTML/markdown/rich text:\n\n  * MUST sanitize before insertion and avoid raw DOM sinks. ([OWASP Cheat Sheet Series][9])\n* If using service workers / PWA:\n\n  * MUST serve over HTTPS and implement a safe caching/update strategy (service workers are powerful request/response proxies). ([MDN Web Docs][10])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### REACT-CONFIG-001: Never embed secrets in the client bundle (env vars are public)\n\nSeverity: Critical (if secrets exposed)\n\nRequired:\n\n* MUST NOT place secrets in React code, in `public/` assets, or in build-time environment variables intended for client consumption.\n* MUST assume any value available to the React app at runtime can be extracted by an attacker.\n\nInsecure patterns:\n\n* Using build-time env vars for secrets:\n\n  * `process.env.REACT_APP_*` containing private keys or credentials.\n  * `import.meta.env.VITE_*` containing secrets.\n* Hard-coded secrets in JS/TS, `.env` committed, or secrets in `public/config.json` served to all users.\n\nDetection hints:\n\n* Search for:\n\n  * `REACT_APP_`, `VITE_`, `NEXT_PUBLIC_`, `process.env.`, `import.meta.env.`\n  * `apiKey`, `secret`, `token`, `private`, `password`, `client_secret`\n* Inspect `public/` for runtime config JSON.\n\nFix:\n\n* Move secrets server-side (API, BFF, serverless function).\n* Use a backend to mint short-lived, scoped tokens if the browser needs to call third-party APIs.\n\nNotes:\n\n* CRA explicitly warns not to store secrets and notes env vars are embedded into the build and visible to anyone inspecting files. ([create-react-app.dev][1])\n* Vite explicitly notes that variables exposed to client code end up in the client bundle and should not contain sensitive info. ([vitejs][11])\n\n---\n\n### REACT-XSS-001: Do not use `dangerouslySetInnerHTML` with untrusted content (sanitize or avoid)\n\nSeverity: High (Only if you can prove attacker-controlled HTML reaches it)\n\nRequired:\n\n* MUST avoid `dangerouslySetInnerHTML` unless absolutely necessary.\n* If it must be used:\n\n  * MUST sanitize untrusted HTML with a proven sanitizer (e.g., DOMPurify) and an allowlist-oriented configuration.\n  * MUST keep the sanitization logic centralized and heavily reviewed.\n  * SHOULD add a CSP and consider Trusted Types (see REACT-TT-001).\n\nInsecure patterns:\n\n* `<div dangerouslySetInnerHTML={{ __html: userHtml }} />` where `userHtml` is from API/URL/storage.\n* “Sanitization” done with regexes, ad-hoc stripping, or incomplete allowlists.\n\nDetection hints:\n\n* Grep: `dangerouslySetInnerHTML`, `__html:`\n* Trace the origin of the HTML string (API/CMS/URL/localStorage).\n\nFix:\n\n* Replace with safe rendering:\n\n  * Render structured data as React elements/components instead of HTML strings.\n  * If rich text is required, sanitize with DOMPurify (or equivalent) and render the sanitized output.\n* Add CSP; remove dangerous sinks where possible.\n\nNotes:\n\n* React explicitly warns that `dangerouslySetInnerHTML` is dangerous and can introduce XSS if misused. ([React][12])\n* OWASP explicitly calls out React’s `dangerouslySetInnerHTML` without sanitization as a common framework “escape hatch” pitfall. ([OWASP Cheat Sheet Series][9])\n* DOMPurify describes itself as an XSS sanitizer for HTML/SVG/MathML. ([GitHub][13])\n\n---\n\n### REACT-XSS-002: Rely on React’s escaping-by-default behavior; do not bypass it\n\nSeverity: High (when bypassed)\n\nRequired:\n\n* MUST render untrusted strings via normal JSX interpolation (`{value}`) and React props, which are escaped by default.\n* MUST NOT build HTML strings from untrusted data and then inject them into the DOM via any means.\n* SHOULD treat any “escape hatch” as high risk and require review.\n\nInsecure patterns:\n\n* Converting untrusted text into HTML and injecting it:\n\n  * `element.innerHTML = userValue`\n  * `document.write(userValue)`\n  * `insertAdjacentHTML(..., userValue)`\n\nDetection hints:\n\n* Grep for DOM sinks: `innerHTML`, `outerHTML`, `insertAdjacentHTML`, `document.write`, `DOMParser`, `createContextualFragment`.\n\nFix:\n\n* Render text content through React (JSX) so it is escaped.\n* If you truly need HTML, sanitize and apply REACT-XSS-001 + REACT-TT-001.\n\nNotes:\n\n* React documentation (JSX) states that React DOM escapes values embedded in JSX before rendering to help prevent injection attacks. ([React][14])\n\n---\n\n### REACT-DOM-001: Avoid DOM XSS injection sinks in React code (use safe alternatives)\n\nSeverity: High\n\nRequired:\n\n* MUST avoid direct DOM injection sinks, even outside React rendering, unless strongly controlled.\n* If a DOM sink is required:\n\n  * MUST ensure inputs are trusted/validated/sanitized.\n  * SHOULD enforce Trusted Types (REACT-TT-001).\n\nInsecure patterns:\n\n* `someEl.innerHTML = untrusted`\n* `document.write(untrusted)`\n* `new DOMParser().parseFromString(untrusted, 'text/html')` followed by insertion\n\nDetection hints:\n\n* Grep for: `innerHTML`, `outerHTML`, `document.write`, `DOMParser`, `Range().createContextualFragment`, `insertAdjacentHTML`\n\nFix:\n\n* Prefer:\n\n  * `textContent` for text insertion.\n  * React rendering rather than manual DOM manipulation.\n  * A vetted sanitizer for any required HTML parsing.\n\nNotes:\n\n* Trusted Types documentation defines HTML sinks like `Element.innerHTML` and `document.write()` as injection sinks that can execute script when given attacker-controlled input. ([MDN Web Docs][3])\n* OWASP HTML5 guidance recommends using `textContent` instead of `innerHTML` for assigning untrusted data. ([OWASP Cheat Sheet Series][4])\n\n---\n\n### REACT-URL-001: Validate and constrain untrusted URLs used in `href`, `src`, navigation, and redirects\n\nSeverity: High Only when you can prove they are attacker controlled\n\nRequired:\n\n* MUST treat any URL derived from untrusted input as dangerous.\n* MUST allowlist schemes and (when applicable) hosts:\n\n  * Typically allow only `https:` (and maybe `http:` for localhost/dev) and relative URLs for in-app navigation.\n  * MUST explicitly block `javascript:` and dangerous `data:` uses unless you have specialized validation and a clear use case.\n* SHOULD prefer same-site relative paths (e.g., `/settings`) over absolute URLs.\n* MUST validate “returnTo/next/redirect” parameters (see REACT-REDIRECT-001).\n\nInsecure patterns:\n\n* `<img src={userProvidedUrl}>...` (can be used for tracking / data exfil; also risky if used for scripts/iframes)\n* `window.location = next`\n* `navigate(next)` where `next` comes from query params without validation\n\nDetection hints:\n\n* Search for:\n\n  * `href={`, `src={`, `window.location`, `location.href`, `window.open`, `navigate(`, `redirectTo`, `returnTo`, `next=`\n* Track whether the value is derived from URL/query/storage/API.\n\nFix:\n\n* Implement a shared `safeUrl()` utility:\n\n  * Parse with `new URL(value, base)`\n  * Enforce scheme allowlist and host allowlist (or enforce same-origin)\n  * For redirects: allow only relative paths (starting with `/`) or a strict allowlist of absolute origins.\n* Fall back to a safe default when validation fails.\n\nNotes:\n\n* OWASP explicitly notes React’s `dangerouslySetInnerHTML` risk and also states React cannot safely handle `javascript:` or `data:` URLs without specialized validation. ([OWASP Cheat Sheet Series][9])\n\n---\n\n### REACT-MARKUP-001: Markdown / rich text rendering must be configured safely\n\nSeverity: Medium\n\nRequired:\n\n* MUST assume markdown/rich text can be attacker-controlled if it comes from users or CMS.\n* MUST ensure raw HTML is not rendered unless sanitized.\n* SHOULD prefer markdown renderers that:\n\n  * Do not allow raw HTML by default, or\n  * Can be configured to disallow raw HTML, or\n  * Sanitize HTML output before rendering.\n\nInsecure patterns:\n\n* Markdown rendering with “raw HTML passthrough” enabled (e.g., options/plugins that allow HTML).\n* Rendering user-provided SVG/MathML/HTML inline without sanitization.\n\nDetection hints:\n\n* Search for common libraries and risky options:\n\n  * `marked`, `markdown-it`, `react-markdown`, `rehype-raw`, `sanitize: false`, `allowDangerousHtml`, etc.\n* Look for `dangerouslySetInnerHTML` used with “markdown output”.\n\nFix:\n\n* Disable raw HTML passthrough.\n* Sanitize output with a proven sanitizer (e.g., DOMPurify) before rendering.\n\nNotes:\n\n* OWASP XSS guidance emphasizes that framework escape hatches require output encoding and/or HTML sanitization. ([OWASP Cheat Sheet Series][9])\n\n---\n\n### REACT-TT-001: Use Trusted Types (with CSP) to harden DOM XSS sinks where feasible\n\nSeverity: Low\n\nRequired:\n\n* SHOULD consider enabling Trusted Types in report-only mode first, then enforce once violations are addressed.\n* SHOULD centralize Trusted Types policies and treat them as high-risk code requiring review.\n* MUST NOT create permissive policies that simply “pass through” untrusted strings.\n\nInsecure patterns:\n\n* A Trusted Types policy that returns the raw string without sanitization for HTML sinks.\n* Many scattered policies across the codebase (hard to audit).\n\nDetection hints:\n\n* Search for:\n\n  * `trustedTypes.createPolicy`\n  * CSP directives: `require-trusted-types-for`, `trusted-types`\n* Search for remaining DOM sinks (REACT-DOM-001).\n\nFix:\n\n* Implement a small number of tightly scoped policies:\n\n  * HTML policy uses sanitizer (DOMPurify or equivalent).\n  * Script URL policy uses strict allowlists.\n* Run in report-only mode, fix violations, then enforce.\n\nNotes:\n\n* MDN describes Trusted Types as a way to ensure input is transformed (commonly sanitized) before being passed to injection sinks, and highlights HTML sinks (`innerHTML`, `document.write`) and JS URL sinks (`script.src`). ([MDN Web Docs][3])\n* The W3C Trusted Types spec frames this as reducing DOM XSS risk by locking down sinks to typed values created by reviewed policies. ([W3C][15])\n\n---\n\n### REACT-CSP-001: Deploy and maintain a CSP as defense-in-depth (especially when rendering untrusted content)\n\nSeverity: Medium to High\n\nRequired:\n\n* SHOULD deploy CSP in production; MUST do so for apps that render untrusted content or integrate third-party scripts.\n* SHOULD avoid `unsafe-inline` and `unsafe-eval` when possible.\n* SHOULD use CSP nonces/hashes for inline scripts if needed, and keep policy realistic.\n* SHOULD use CSP to require/encourage SRI where appropriate.\n\nInsecure patterns:\n\n* No CSP at all on the app shell (SPA entry HTML).\n* CSP that relies on `unsafe-inline`/`unsafe-eval` broadly without justification.\n* `script-src *` or overly broad sources.\n\nDetection hints:\n\n* Look for CSP configuration:\n\n  * Server/CDN config, headers in `index.html` responses, or framework config.\n* If absent in repo, mark as “verify at edge”.\n\nFix:\n\n* Add CSP via HTTP response headers (preferred).\n* Start with report-only to reduce breakage, then enforce.\n\nNotes:\n\n* OWASP describes CSP as “defense in depth” against XSS and notes it can help enforce SRI even on static sites, but should not be the only defense. ([OWASP Cheat Sheet Series][2])\n\n---\n\n### REACT-SRI-001: Use Subresource Integrity (SRI) for third-party scripts and styles (or self-host)\n\nSeverity: Low\n\nRequired:\n\n* MUST treat third-party JS as equivalent to running arbitrary code in your origin.\n* If loading from a CDN or third party:\n\n  * SHOULD use SRI (`integrity=...`) and `crossorigin` where applicable.\n  * SHOULD pin exact versions (avoid “latest” URLs).\n  * SHOULD prefer self-hosting for critical code.\n\nInsecure patterns:\n\n* `<script src=\"https://cdn.example.com/lib/latest.js\"></script>` with no integrity.\n* Tag managers that dynamically load arbitrary scripts without governance.\n\nDetection hints:\n\n* Search in `public/index.html`, templates, or SSR wrappers for:\n\n  * `<script src=`, `<link rel=\"stylesheet\" href=`\n  * Tag manager snippets (GTM, Segment, etc.)\n* Identify scripts loaded dynamically in runtime JS.\n\nFix:\n\n* Add SRI hashes for stable third-party assets or self-host.\n* Apply governance controls for tag managers (see REACT-3P-001).\n\nNotes:\n\n* MDN describes SRI as a security feature enabling browsers to verify fetched resources (e.g., from a CDN) haven’t been manipulated by checking a cryptographic hash. ([MDN Web Docs][7])\n* OWASP CSP guidance notes CSP can enforce SRI and is useful even on static sites. ([OWASP Cheat Sheet Series][2])\n\n---\n\n### REACT-3P-001: Third-party JavaScript and tag managers must be minimized and governed\n\nSeverity: High\n\nRequired:\n\n* MUST minimize third-party scripts and treat each as a supply-chain risk.\n* MUST know exactly what third-party JS executes in your origin and why.\n* SHOULD implement governance:\n\n  * Review and pin versions (or mirror in-house).\n  * Restrict data access (data-layer approach).\n  * Use SRI and CSP; consider sandboxing untrusted UI in iframes where possible.\n\nInsecure patterns:\n\n* Unreviewed analytics/ads scripts running with full access to DOM, cookies, storage, and user data.\n* Tag managers that can be changed by non-engineering roles with no change control.\n\nDetection hints:\n\n* Search for common vendor snippets in HTML/JS:\n\n  * GTM, Segment, Hotjar, FullStory, etc.\n* Look for dynamic script insertion:\n\n  * `document.createElement('script')`, `.src = ...`, `.appendChild(script)`\n\nFix:\n\n* Reduce to only necessary vendors.\n* Where feasible:\n\n  * Self-host or mirror scripts.\n  * Use SRI.\n  * Limit data exposure via a controlled data layer.\n\nNotes:\n\n* OWASP notes third-party JS server compromise can inject malicious JS, and highlights risks like arbitrary code execution and disclosure of sensitive info to third parties. ([OWASP Cheat Sheet Series][5])\n\n---\n\n### REACT-AUTH-001: Token and session handling must be resilient to XSS (avoid sensitive storage in Web Storage)\n\nSeverity: Medium\n\nRequired:\n\n* SHOULD avoid storing session identifiers or long-lived tokens in `localStorage` (and generally in Web Storage) because XSS can exfiltrate them.\n* If tokens must exist client-side:\n\n  * SHOULD prefer in-memory storage with short lifetimes and refresh mechanisms.\n  * MUST scope and rotate tokens; avoid long-lived bearer tokens in persistent storage.\n* SHOULD prefer HTTPOnly cookies for session tokens when possible (requires CSRF strategy: see REACT-CSRF-001).\n\nInsecure patterns:\n\n* `localStorage.setItem('token', ...)` / `sessionStorage.setItem('token', ...)` for auth tokens.\n* Persisting refresh tokens in `localStorage`.\n* Treating data from Web Storage as trusted.\n\nDetection hints:\n\n* Grep for: `localStorage.`, `sessionStorage.`, `setItem(`, `getItem(`, `token`, `jwt`, `refresh`\n* Search auth code for “remember me” storing tokens persistently.\n\nFix:\n\n* Move to HTTPOnly cookies (server change) + CSRF protections, or use short-lived in-memory tokens.\n* Reduce token scope and lifetime.\n\nNotes:\n\n* OWASP HTML5 guidance recommends avoiding sensitive info and session identifiers in local storage and warns that a single XSS can steal all data in Web Storage. ([OWASP Cheat Sheet Series][4])\n* OAuth browser-based apps guidance discusses that tokens stored in persistent browser storage like localStorage can be accessible to malicious JS (e.g., via XSS). ([IETF Datatracker][16])\n\n---\n\n### REACT-CSRF-001: Cookie-authenticated, state-changing requests MUST be CSRF-protected\n\nSeverity: High\n\nNOTE: If the application does not use cookie based auth (using Authentication header for example), then CSRF is not a concern.\n\nRequired:\n\n* If the app relies on cookies for authentication:\n\n  * MUST protect state-changing requests (POST/PUT/PATCH/DELETE) against CSRF.\n  * SHOULD include a CSRF token mechanism (synchronizer token or double-submit cookie) or other robust pattern appropriate to the backend.\n  * SHOULD use SameSite cookies as defense-in-depth, not as the sole defense.\n\nInsecure patterns:\n\n* `fetch('/api/transfer', { method: 'POST', credentials: 'include' })` with no CSRF token/header, relying only on cookies.\n* Using GET for state-changing operations.\n\nDetection hints:\n\n* Enumerate state-changing network calls and check:\n\n  * Is `credentials: 'include'` or `withCredentials: true` used?\n  * Is a CSRF token header included (e.g., `X-CSRF-Token`)?\n* Search for “csrf” utilities; if absent, treat as suspicious.\n\nFix:\n\n* Add CSRF token flow:\n\n  * Fetch token from a safe endpoint and attach to state-changing requests.\n  * Validate server-side.\n* Keep SameSite cookies and Origin/Referer validation as defense-in-depth.\n\nNotes:\n\n* OWASP CSRF guidance explains SameSite behavior (Lax/Strict/None) as a defense-in-depth technique and why Lax is often the usability/security balance, but it is not a complete substitute for CSRF protections. ([OWASP Cheat Sheet Series][6])\n\n---\n\n### REACT-AUTHZ-001: Do not rely on frontend-only authorization\n\nSeverity: High (only if used as primary protection)\n\nRequired:\n\n* MUST treat all frontend authorization checks as UX only.\n* MUST enforce authorization on the server for any protected resource or action.\n\nInsecure patterns:\n\n* “Protected” actions hidden in UI but callable by API without server checks.\n* Client checks like `if (user.isAdmin) { showAdminPanel(); }` with no server-side enforcement.\n\nDetection hints:\n\n* Look for UI gating around sensitive actions and verify server endpoints enforce authorization.\n* In a frontend-only audit, report as “client checks are not security; verify backend”.\n\nFix:\n\n* Add/confirm server-side authorization checks.\n* Keep frontend gating only as convenience.\n\nNotes:\n\n* This is a general web app security property; React cannot protect server resources by itself.\n\n---\n\n### REACT-NET-001: Prevent data exfiltration and credential leakage via dynamic outbound requests\n\nSeverity: Medium to High\n\nRequired:\n\n* MUST avoid making authenticated requests to attacker-controlled origins.\n* SHOULD avoid allowing user input to control request destination (scheme/host/port).\n* SHOULD centralize network clients (fetch/axios) with:\n\n  * fixed `baseURL` (or strict allowlist),\n  * strict handling of redirects,\n  * explicit `credentials` usage.\n\nInsecure patterns:\n\n* `fetch(userProvidedUrl, { credentials: 'include' })`\n* `axios.create({ baseURL: userProvidedBase })`\n* “URL fetch/preview” features in the client that hit arbitrary domains with sensitive headers.\n\nDetection hints:\n\n* Search for `fetch(` / `axios(` where the first argument or `baseURL` is derived from:\n\n  * query params, localStorage, API responses, postMessage\n* Search for `credentials: 'include'`, `withCredentials: true`.\n\nFix:\n\n* Enforce destination allowlists; disallow cross-origin requests unless explicitly required.\n* Strip credentials/Authorization headers for any non-allowlisted destination.\n\nNotes:\n\n* Even if the browser limits some cross-origin behavior, leaking tokens/headers to untrusted endpoints is still a common failure mode.\n\n---\n\n### REACT-REDIRECT-001: Prevent open redirects and untrusted navigation\n\nSeverity: Medium\n\nRequired:\n\n* MUST validate redirect/navigation targets derived from untrusted input (`next`, `returnTo`, `redirect`).\n* SHOULD only allow same-site relative paths, or a strict allowlist of trusted origins for absolute URLs.\n\nInsecure patterns:\n\n* `window.location.href = new URLSearchParams(location.search).get('next')`\n* `navigate(next)` where `next` comes from query params.\n\nDetection hints:\n\n* Search for: `next`, `returnTo`, `redirect`, `window.location`, `navigate(`\n* Trace origin of the redirect target.\n\nFix:\n\n* Only allow relative paths (`/^\\/[^\\s]*$/`) or allowlisted origins.\n* Fall back to a safe default (e.g., `/`) when invalid.\n\nNotes:\n\n* Open redirects are frequently used in phishing and can undermine SSO/OAuth flows.\n\n---\n\n### REACT-SW-001: Service workers are high-privilege; require HTTPS and safe caching/update rules\n\nSeverity: Medium\n\nRequired:\n\n* MUST serve service workers over HTTPS (except `localhost` dev), and deploy only in secure contexts.\n* MUST avoid caching sensitive authenticated API responses unless explicitly designed and threat-modeled.\n* SHOULD implement safe update strategy (prompt reload, versioned caches, remove old caches on activate).\n\nInsecure patterns:\n\n* Registering a service worker for an authenticated app and caching “everything” indiscriminately.\n* Long-lived caches containing PII or user-specific content shared across accounts.\n\nDetection hints:\n\n* Search for:\n\n  * `navigator.serviceWorker.register`\n  * `workbox`, `precacheAndRoute`, custom `fetch` handlers\n* Inspect caching patterns (`caches.open`, `cache.put`, `respondWith`).\n\nFix:\n\n* Restrict caching to static assets only (JS/CSS/images) unless you have a designed offline model.\n* Ensure cache keys are user-scoped if user-specific data must be cached.\n* Provide a clear update mechanism.\n\nNotes:\n\n* MDN notes service workers require HTTPS for security reasons and act like a proxy for requests/responses. ([MDN Web Docs][10])\n* “Secure contexts” exist to prevent MITM attackers from accessing powerful APIs; service workers are an example of such a powerful feature. ([MDN Web Docs][18])\n\n---\n\n### REACT-HEADERS-001: Ensure essential security headers are set for the React app shell (app or edge)\n\nSeverity: Medium\n\nRequired (typical SPA served from an origin):\n\n* SHOULD set:\n\n  * CSP (`Content-Security-Policy`)\n  * `X-Content-Type-Options: nosniff`\n  * Clickjacking protection (`frame-ancestors` in CSP and/or `X-Frame-Options`)\n  * `Referrer-Policy`\n  * `Permissions-Policy` as appropriate\n* MUST ensure these are set somewhere (CDN/edge/server), even if not in repo.\n\nInsecure patterns:\n\n* No security headers anywhere (app or edge).\n* CSP missing on apps that render untrusted content or use third-party scripts.\n\nDetection hints:\n\n* Check server/CDN config in repo (nginx, Cloudflare, Vercel config, etc.).\n* If absent, flag as “verify at runtime/edge”.\n\nFix:\n\n* Set headers centrally at the edge.\n* Keep CSP realistic and iterative (report-only → enforce).\n\nNotes:\n\n* MDN clickjacking guidance discusses defenses including `X-Frame-Options` and CSP `frame-ancestors`. ([MDN Web Docs][8])\n* OWASP CSP guidance explains delivery via response headers and recommends headers as the preferred mechanism. ([OWASP Cheat Sheet Series][2])\n\n---\n\n### REACT-POSTMSG-001: `postMessage` must validate origin and treat payload as untrusted data\n\nSeverity: Medium to High (depends on what messages can do)\n\nRequired:\n\n* MUST specify exact `targetOrigin` when sending messages (not `*`) unless there is a strict reason.\n* MUST validate `event.origin` on receipt and validate message shape.\n* MUST NOT evaluate message data as code or insert it into the DOM as HTML.\n\nInsecure patterns:\n\n* `window.postMessage(data, '*')` to unknown targets.\n* Receiving:\n\n  * `window.addEventListener('message', (e) => { eval(e.data) })`\n  * `element.innerHTML = e.data`\n\nDetection hints:\n\n* Search: `postMessage(`, `addEventListener('message'`\n* Check for origin checks and safe handling.\n\nFix:\n\n* Add strict origin allowlists and schema validation (e.g., zod).\n* Treat message payload strictly as data; render safely via React.\n\nNotes:\n\n* OWASP HTML5 guidance recommends specifying expected origin for `postMessage`, checking sender origin, validating data, and avoiding eval/innerHTML with message content. ([OWASP Cheat Sheet Series][4])\n\n---\n\n### REACT-FILE-001: File uploads and previews must not create client-side active content vulnerabilities\n\nSeverity: Medium (can be High if stored-XSS possible)\n\nRequired:\n\n* MUST treat user-uploaded files and previews as potentially malicious.\n* MUST NOT render uploaded HTML/SVG/other active content inline unless sanitized and explicitly required.\n* SHOULD validate file types client-side for UX, but MUST rely on server-side validation for security.\n\nInsecure patterns:\n\n* Rendering user-uploaded HTML as content.\n* Inline rendering of untrusted SVG/HTML via `dangerouslySetInnerHTML` or `<iframe srcdoc=...>` without sanitization.\n\nDetection hints:\n\n* Search for upload components and preview logic:\n\n  * `input type=\"file\"`, `FileReader`, `URL.createObjectURL`, `<iframe>`, `<object>`, `<embed>`.\n* Trace where uploaded content is later displayed.\n\nFix:\n\n* Restrict accepted types, sanitize where needed, and prefer download/attachment flows for risky types.\n* Ensure server enforces the real policy (type checking, renaming, scanning, storing outside webroot).\n\nNotes:\n\n* OWASP file upload guidance highlights allowlisting extensions, validating file type, generating filenames, limiting size, storing outside webroot, and considering “client-side active content (XSS, CSRF, etc.)” when files are publicly retrievable. ([OWASP Cheat Sheet Series][19])\n\n---\n\n### REACT-SUPPLY-001: Dependency and supply-chain hygiene (frontend + build tooling)\n\nSeverity: Low\n\nRequired:\n\n* MUST use a lockfile and enforce reproducible installs in CI.\n* SHOULD regularly audit dependencies and respond quickly to advisories for:\n\n  * React, react-dom, router libs, build tooling (Vite/Webpack), sanitizers, auth libs, etc.\n* SHOULD reduce exposure to install-time script attacks and typosquatting risk.\n\nAudit focus:\n\n* CI should use `npm ci` (or Yarn frozen lockfile / pnpm equivalent) to prevent drift.\n* Use vulnerability scanning (`npm audit`, GitHub Dependabot/alerts, etc.).\n\nInsecure patterns:\n\n* No lockfile or lockfile ignored in CI.\n* `npm install` in CI producing non-reproducible builds.\n* Unpinned or unreviewed high-risk deps; sudden major updates without review.\n* Blindly running install scripts from third-party packages.\n\nDetection hints:\n\n* Check for lockfiles: `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`.\n* Check CI scripts for `npm install` vs `npm ci`.\n* Search for `postinstall` scripts and suspicious build steps.\n\nFix:\n\n* Use lockfile and enforce it in CI (e.g., `npm ci`).\n* Run audits regularly; pin/upgrade responsibly.\n* Consider restricting install scripts where feasible.\n\nNotes:\n\n* npm docs describe `npm audit` as submitting the project dependency tree to the registry to receive a report of known vulnerabilities and (optionally) applying remediations via `npm audit fix`, while noting some vulns require manual review. ([npm Docs][20])\n* npm docs describe `npm ci` as intended for automated/CI environments, requiring an existing lockfile and failing if `package.json` and lockfile do not match. ([npm Docs][21])\n* OWASP NPM security guidance recommends enforcing the lockfile and explicitly calls out `npm ci` / `yarn install --frozen-lockfile` to abort on inconsistencies, and highlights the risk of install-time scripts and the option to use `--ignore-scripts` to reduce attack surface. ([OWASP Cheat Sheet Series][22])\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* Raw HTML / XSS escape hatches:\n\n  * `dangerouslySetInnerHTML`, `__html:`\n  * Markdown HTML passthrough flags: `rehype-raw`, `allowDangerousHtml`, `sanitize: false`\n* DOM XSS sinks:\n\n  * `innerHTML`, `outerHTML`, `insertAdjacentHTML`, `document.write`, `DOMParser`, `createContextualFragment`\n* Dangerous JS execution:\n\n  * `eval(`, `new Function(`, `setTimeout(\"`, `setInterval(\"`\n* Untrusted URL injection / navigation:\n\n  * `href={` / `src={` with untrusted values\n  * `window.location`, `location.href`, `window.open`, `navigate(`\n  * Query params: `next`, `returnTo`, `redirect`\n* Token/session risk:\n\n  * `localStorage.setItem`, `sessionStorage.setItem`, `getItem(` with `token`, `jwt`, `refresh`\n* Cookie/CSRF coupling:\n\n  * `credentials: 'include'`, `withCredentials: true` on state-changing requests without CSRF headers\n* Third-party scripts:\n\n  * `<script src=...>` in `public/index.html`\n  * Tag manager snippets and dynamic script insertion\n* Service workers:\n\n  * `navigator.serviceWorker.register`, Workbox usage, custom `fetch` handlers\n* postMessage:\n\n  * `postMessage(` with `*`, missing `event.origin` checks\n* Supply chain:\n\n  * Missing lockfile, CI uses `npm install`, no audit step, risky postinstall scripts\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (React escape hatch vs DOM sink vs navigation vs storage)\n* protective controls present (sanitization, allowlists, CSP/Trusted Types, CSRF tokens, headers, governance)\n\n---\n\n## 6) Sources (accessed 2026-01-26)\n\nPrimary React documentation:\n\n* React 19 stable announcement — `https://react.dev/blog/2024/12/05/react-19` ([React][23])\n* React DOM docs: `dangerouslySetInnerHTML` warning — `https://react.dev/reference/react-dom/components/common#dangerouslysetting-the-inner-html` ([React][12])\n* React (legacy) JSX escaping statement — `https://legacy.reactjs.org/docs/introducing-jsx.html` ([React][14])\n\nOWASP Cheat Sheet Series:\n\n* Cross Site Scripting Prevention (framework escape hatches; React `dangerouslySetInnerHTML`; URL validation notes) — `https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][9])\n* Content Security Policy — `https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][2])\n* Cross-Site Request Forgery Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][6])\n* HTML5 Security (Web Storage, postMessage, tabnabbing, sandboxed frames) — `https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][4])\n* Third Party JavaScript Management — `https://cheatsheetseries.owasp.org/cheatsheets/Third_Party_Javascript_Management_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][5])\n* File Upload — `https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][19])\n* NPM Security best practices — `https://cheatsheetseries.owasp.org/cheatsheets/NPM_Security_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][22])\n\nBrowser / platform references (MDN, W3C):\n\n* Trusted Types API — `https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API` ([MDN Web Docs][3])\n* W3C Trusted Types spec — `https://www.w3.org/TR/trusted-types/` ([W3C][15])\n* Subresource Integrity — `https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity` ([MDN Web Docs][7])\n* Clickjacking defenses overview — `https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/Clickjacking` ([MDN Web Docs][8])\n* Using Service Workers (HTTPS requirement; proxy-like behavior) — `https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers` ([MDN Web Docs][10])\n* Secure contexts (powerful APIs restricted to HTTPS) — `https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Secure_Contexts` ([MDN Web Docs][18])\n* Link `rel` values (noopener/noreferrer) — `https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel` ([MDN Web Docs][17])\n\nBuild tooling / env exposure references:\n\n* Create React App env variables warning — `https://create-react-app.dev/docs/adding-custom-environment-variables/` ([create-react-app.dev][1])\n* Vite env variables security notes — `https://vite.dev/guide/env-and-mode` ([vitejs][11])\n\nAuth/token storage guidance:\n\n* OAuth 2.0 for Browser-Based Apps (token storage discussion) — `https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps` ([IETF Datatracker][16])\n\nDependency tooling references:\n\n* npm audit docs — `https://docs.npmjs.com/cli/v10/commands/npm-audit/` ([npm Docs][20])\n* npm ci docs — `https://docs.npmjs.com/cli/v10/commands/npm-ci/` ([npm Docs][21])\n\nSanitizer reference:\n\n* DOMPurify — `https://github.com/cure53/DOMPurify` ([GitHub][13])\n\n[1]: https://create-react-app.dev/docs/adding-custom-environment-variables/ \"Adding Custom Environment Variables | Create React App\"\n[2]: https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html \"Content Security Policy - OWASP Cheat Sheet Series\"\n[3]: https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API \"Trusted Types API - Web APIs | MDN\"\n[4]: https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html \"HTML5 Security - OWASP Cheat Sheet Series\"\n[5]: https://cheatsheetseries.owasp.org/cheatsheets/Third_Party_Javascript_Management_Cheat_Sheet.html \"Third Party Javascript Management - OWASP Cheat Sheet Series\"\n[6]: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html \"Cross-Site Request Forgery Prevention - OWASP Cheat Sheet Series\"\n[7]: https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity \"Subresource Integrity - Security | MDN\"\n[8]: https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/Clickjacking \"Clickjacking - Security | MDN\"\n[9]: https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html \"Cross Site Scripting Prevention - OWASP Cheat Sheet Series\"\n[10]: https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers \"Using Service Workers - Web APIs | MDN\"\n[11]: https://vite.dev/guide/env-and-mode \"Env Variables and Modes | Vite\"\n[12]: https://react.dev/reference/react-dom/components/common \"Common components (e.g. <div>) – React\"\n[13]: https://github.com/cure53/DOMPurify \"GitHub - cure53/DOMPurify: DOMPurify - a DOM-only, super-fast, uber-tolerant XSS sanitizer for HTML, MathML and SVG. DOMPurify works with a secure default, but offers a lot of configurability and hooks. Demo:\"\n[14]: https://legacy.reactjs.org/docs/introducing-jsx.html \"Introducing JSX – React\"\n[15]: https://www.w3.org/TR/trusted-types/ \"Trusted Types\"\n[16]: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps \"\n\n                draft-ietf-oauth-browser-based-apps-26\n\n        \"\n[17]: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel \"HTML attribute: rel - HTML | MDN\"\n[18]: https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Secure_Contexts \"Secure contexts - Security | MDN\"\n[19]: https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html \"File Upload - OWASP Cheat Sheet Series\"\n[20]: https://docs.npmjs.com/cli/v10/commands/npm-audit \"npm-audit | npm Docs\"\n[21]: https://docs.npmjs.com/cli/v10/commands/npm-ci \"npm-ci | npm Docs\"\n[22]: https://cheatsheetseries.owasp.org/cheatsheets/NPM_Security_Cheat_Sheet.html \"NPM Security - OWASP Cheat Sheet Series\"\n[23]: https://react.dev/blog/2024/12/05/react-19 \"React v19 – React\"\n\n<!-- File: core/skills/builtin/security-best-practices/references/javascript-typescript-vue-web-frontend-security.md (Tokens: ~7369 | Category: anthropic-skill) -->\n# Vue.js Web Security Spec (Vue 3.x, TypeScript/JavaScript, common tooling: Vite)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new Vue code.\n2. **Security review / vulnerability hunting** in existing Vue code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session cookies, auth tokens).\n* MUST NOT “fix” security by disabling protections (e.g., weakening CSP, turning on unsafe template compilation, using `v-html` as a shortcut, bypassing backend auth, or “just store the token in localStorage”).\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and configuration values that justify the claim.\n* MUST treat uncertainty honestly: if a protection might exist at the edge (CDN, reverse proxy, WAF, server headers), report it as “not visible in repo; verify runtime/infra config”.\n* MUST remember the frontend trust model: **any code shipped to browsers is attacker-readable and attacker-modifiable**. Secrets and “security enforcement” cannot rely on frontend-only logic.\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new Vue code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default framework features and proven libraries over custom security code.\n* MUST avoid introducing new risky sinks (runtime template compilation, `v-html` / `innerHTML`, unsafe URL navigation, dynamic script injection, etc.). ([Vue.js][1])\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a Vue repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. Build/deploy entrypoints and hosting config (Docker, CI, static hosting, SSR server).\n2. Secrets exposure (env usage, `.env*`, hard-coded keys). ([vitejs][2])\n3. XSS surface: templates, `v-html` / `innerHTML`, URL/style injection, DOM APIs. ([Vue.js][1])\n4. Auth/session handling in the browser (token storage, credentialed requests, CSRF integration). ([Vue.js][1])\n5. Routing/navigation (open redirects, “return_to/next”, unsafe external navigation). ([Vue.js][1])\n6. Third-party scripts and content (CDN assets, analytics, widgets, iframes). ([Vue.js][1])\n7. Security headers and browser hardening expectations (CSP, clickjacking). ([Vue.js][1])\n8. SSR-specific concerns (state serialization, template boundaries) when applicable. ([Vue.js][1])\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nIn a Vue app, untrusted input includes (non-exhaustive):\n\n* Anything from APIs: `fetch`, `axios`, GraphQL responses, webhooks, third-party SDKs.\n* Router-controlled data: `route.params`, `route.query`, `route.hash`, and anything derived from `window.location`.\n* User-controlled persisted content: DB-backed content displayed in the UI (comments, profiles, CMS content).\n* Browser-controlled storage: `localStorage`, `sessionStorage`, `IndexedDB`.\n* Cross-window messages: `postMessage` inputs.\n* Anything that can be influenced by an attacker through DOM clobbering or injected HTML (especially if Vue is mounted onto non-sterile DOM). ([Vue.js][1])\n\n### 2.2 State-changing action (frontend perspective)\n\nAn action is state-changing if it can:\n\n* Create/update/delete data via API calls.\n* Change authentication/session state (login, logout, refresh token).\n* Trigger privileged operations (payments, admin actions).\n* Cause side effects (sending emails, triggering webhooks, changing account settings).\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + component/function + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common Vue/front-end misconfigurations.\n\n* MUST ship a **production build** (not a development build or dev server). ([Vue.js][3])\n* MUST NOT ship secrets in frontend bundles; treat all client-exposed env variables as public. ([vitejs][2])\n* MUST NOT render non-trusted templates or allow user-provided Vue templates (equivalent to arbitrary JS execution). ([Vue.js][1])\n* SHOULD avoid raw HTML injection (`v-html`, `innerHTML`) unless content is trusted or strongly sandboxed. ([Vue.js][1])\n* SHOULD deploy baseline security headers (especially CSP and clickjacking defenses) at the server/CDN layer. ([OWASP Cheat Sheet Series][4])\n* SHOULD use safe auth patterns (prefer HttpOnly cookies for session tokens; coordinate with backend on CSRF). ([Vue.js][1])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### VUE-DEPLOY-001: Do not run dev/preview servers in production\n\nSeverity: High\n\nRequired:\n\n* MUST NOT deploy the Vite/Vue dev server (`vite`, `npm run dev`, HMR) as the production server.\n* MUST NOT use `vite preview` as a production server. ([vitejs][5])\n* MUST build (`vite build`) and serve the built assets using a production-grade static server/CDN, or a production SSR server if you are doing SSR. ([vitejs][6])\n\nInsecure patterns:\n\n* Docker/Procfile/systemd running `vite`, `npm run dev`, or `vite preview` as the production entrypoint.\n* Publicly exposed HMR endpoints.\n\nDetection hints:\n\n* Search: `vite`, `npm run dev`, `pnpm dev`, `yarn dev`, `vite preview`, `vue-cli-service serve`.\n* Check Docker `CMD`, `ENTRYPOINT`, CI deploy scripts, platform config.\n\nFix:\n\n* Build artifacts with `vite build`.\n* Serve `dist/` with hardened hosting (CDN/static server) or integrate into your backend server as static assets.\n\nNotes:\n\n* Using dev/preview servers locally is fine; only flag if it is the production entrypoint.\n\n---\n\n### VUE-DEPLOY-002: Use Vue production builds and keep devtools off in production\n\nSeverity: Medium (High if production devtools/debug hooks are enabled)\n\nRequired:\n\n* If loading Vue from CDN/self-host without a bundler, MUST use the `.prod.js` builds in production. ([Vue.js][3])\n* SHOULD ensure production bundles do not enable Vue devtools in production builds, and SHOULD not intentionally enable production devtools flags. ([Vue.js][7])\n\nInsecure patterns:\n\n* Production includes development build artifacts.\n* Explicitly enabling production devtools/diagnostic hooks.\n\nDetection hints:\n\n* Search HTML for `vue.global.js` / non-`.prod.js` variants when using CDN builds.\n* Search build config for Vue feature flags like `__VUE_PROD_DEVTOOLS__`. ([Vue.js][7])\n\nFix:\n\n* Switch to production build artifacts and ensure compile-time flags are configured for production.\n\n---\n\n### VUE-SECRETS-001: Never ship secrets in frontend code or env variables\n\nSeverity: High (Critical if real credentials are exposed)\n\nRequired:\n\n* MUST treat all frontend code and configuration as public.\n* MUST NOT embed secrets in:\n\n  * source code\n  * `.env` files committed to repo\n  * `import.meta.env.*` variables included in the bundle\n* MUST assume any env var that ends up in the client bundle is attacker-readable. ([vitejs][2])\n\nInsecure patterns:\n\n* `VITE_API_KEY=...` containing a true secret (not just a public identifier).\n* Hard-coded API keys, private tokens, service credentials, signing keys in JS/TS.\n\nDetection hints:\n\n* Search: `VITE_`, `import.meta.env`, `.env`, `.env.production`, `.env.*.local`.\n* Grep for `API_KEY`, `SECRET`, `TOKEN`, `PRIVATE_KEY`, `BEGIN`, `sk-`, `AKIA`, etc.\n\nFix:\n\n* Move secrets to backend/edge functions.\n* Use backend-minted short-lived tokens for the browser when needed.\n\nNotes:\n\n* Vite specifically warns that `.env.*.local` should be gitignored and that `VITE_*` vars end up in the client bundle, so they must not contain sensitive info. ([vitejs][2])\n\n---\n\n### VUE-SECRETS-002: Do not broaden Vite env exposure\n\nSeverity: High\n\nRequired:\n\n* MUST NOT configure Vite to expose all environment variables to the client.\n* SHOULD keep `envPrefix` strict and explicit.\n\nInsecure patterns:\n\n* Setting `envPrefix` to overly broad values (or `''`) to “make env vars work”.\n* Custom scripts that inject server secrets into global variables in HTML at build time.\n\nDetection hints:\n\n* Check `vite.config.*` for `envPrefix`.\n* Look for `define: { 'process.env': ... }` or manual injection into `window.__CONFIG__`.\n\nFix:\n\n* Keep secrets server-side.\n* Only expose non-sensitive values intentionally designed to be public.\n\nNotes:\n\n* Vite’s docs explain that only prefixed variables are exposed and that exposed variables land in the client bundle. ([vitejs][2])\n\n---\n\n### VUE-XSS-001: Prefer Vue’s default escaping; avoid raw HTML injection\n\nSeverity: High\n\nRequired:\n\n* MUST rely on Vue’s automatic escaping for text interpolation and attribute binding where possible. ([Vue.js][1])\n* MUST NOT render user-provided HTML via:\n\n  * `v-html`\n  * `innerHTML` in render functions / JSX\n  * direct DOM APIs (`element.innerHTML`, `insertAdjacentHTML`)\n    unless the HTML is trusted or robustly sanitized and the risk is explicitly accepted. ([Vue.js][1])\n\nInsecure patterns:\n\n* `<div v-html=\"userProvidedHtml\"></div>`\n* `h('div', { innerHTML: userProvidedHtml })`\n* `<div innerHTML={userProvidedHtml}></div>`\n* `el.innerHTML = untrusted`\n\nDetection hints:\n\n* Search: `v-html`, `innerHTML`, `insertAdjacentHTML`, `DOMParser`, `document.write`.\n\nFix:\n\n* Render untrusted content as text (interpolation).\n* If HTML rendering is required (e.g., Markdown), sanitize with a well-maintained HTML sanitizer and apply defense-in-depth (CSP, Trusted Types). ([Vue.js][1])\n\nNotes:\n\n* Vue’s docs explicitly warn that user-provided HTML is never “100% safe” unless sandboxed or strictly self-only exposure. ([Vue.js][1])\n\n---\n\n### VUE-XSS-002: Never use non-trusted templates (client-side template/code injection)\n\nSeverity: Critical\n\nRequired:\n\n* MUST NOT use non-trusted content as a Vue component template.\n* MUST treat “user can write a Vue template” as “user can execute arbitrary JavaScript in your app”, and potentially in SSR contexts too. ([Vue.js][1])\n* SHOULD prefer the runtime-only build (templates compiled at build time) and avoid shipping the runtime compiler unless you have a vetted need.\n\nInsecure patterns:\n\n* `createApp({ template: '<div>' + userProvidedString + '</div>' }).mount(...)`\n* Storing templates in DB and compiling/rendering them in the browser.\n* Admin/CMS features that allow entering Vue template syntax.\n\nDetection hints:\n\n* Search: `template:` where the value is not a static string.\n* Search: `@vue/compiler-dom`, `compile(`, “runtime compiler” build selection, dynamic SFC compilation.\n* Search for “template editor”, “custom template”, “theme HTML” features.\n\nFix:\n\n* Treat templates as code: keep them developer-controlled.\n* If end-user customization is required, use a safe format (restricted Markdown subset) rendered via a sanitizer, or isolate in a sandboxed iframe.\n\n---\n\n### VUE-XSS-003: Do not mount Vue onto DOM that may contain user-provided server-rendered HTML\n\nSeverity: Medium\n\nRequired:\n\n* MUST NOT mount Vue on nodes that may contain server-rendered and user-provided content (because attacker-controlled HTML that is “safe as HTML” may become unsafe as a Vue template). ([Vue.js][1])\n* SHOULD mount Vue into a “sterile” root element and render the app’s DOM from Vue-controlled templates/components.\n\nInsecure patterns:\n\n* Server renders user content into `#app`, then Vue mounts on `#app` and compiles/interprets that DOM as a template.\n* “Sprinkling Vue” on large server-rendered pages that include user-generated content.\n\nDetection hints:\n\n* Check server templates (e.g., Rails/Django/Express templates) for user HTML inserted inside the Vue mount root.\n* Look for `mount('#app')` where `#app` includes server-rendered UGC.\n\nFix:\n\n* Move user-rendered HTML outside the Vue mount root, or render it in a safe way (text/sanitized HTML) from Vue components.\n\n---\n\n### VUE-XSS-004: Prevent URL injection in bindings and navigations\n\nSeverity: High\n\nRequired:\n\n* MUST validate/sanitize any user-influenced URL before binding to navigation sinks (`href`, `src`, `action`, `window.location`, `window.open`, router navigation to external).\n* MUST specifically prevent `javascript:` URL execution in bindings like `<a :href=\"userProvidedUrl\">`. ([Vue.js][1])\n* SHOULD validate protocol and destination (allowlist `https:` and expected hosts; allow `mailto:`/`tel:` only if intended).\n\nInsecure patterns:\n\n* `<iframe :src=\"userProvidedUrl\">`\n* `window.location = route.query.next`\n* `window.open(userProvidedUrl)`\n\nDetection hints:\n\n* Search: `:href=`, `:src=`, `window.location`, `location.href`, `window.open`, `router.push(` with untrusted input.\n* Look for `next`, `return_to`, `redirect` query params.\n\nFix:\n\n* Prefer internal navigation via route names/paths you control.\n* For external URLs: parse with `new URL(...)`, allowlist protocol/host, reject `javascript:` and other dangerous schemes.\n* Sanitize and validate on the backend before storing user URLs (Vue docs explicitly recommend backend sanitization). ([Vue.js][1])\n\n---\n\n### VUE-XSS-005: Prevent style/CSS injection and UI redress\n\nSeverity: Low\n\nRequired:\n\n* MUST NOT bind attacker-controlled CSS strings broadly (e.g., `:style=\"userProvidedStyles\"`).\n* SHOULD use Vue’s style object syntax and only allow safe, specific properties if user customization is needed. ([Vue.js][1])\n* SHOULD isolate “user can control layout/CSS” features inside sandboxed iframes.\n\nInsecure patterns:\n\n* `:style=\"userProvidedStyles\"` where styles are attacker-controlled.\n* Rendering user-provided `<style>` content (even if Vue blocks some patterns, don’t try to work around it).\n\nDetection hints:\n\n* Search: `:style=\"` bound to non-constant variables that originate from API/user content.\n* Search for “custom CSS”, “theme editor”, “profile CSS”.\n\nFix:\n\n* Allowlist properties and values; avoid raw style strings.\n* Use sandboxed iframes for rich user customization.\n\n---\n\n### VUE-XSS-006: Never bind user-provided JavaScript into event handler attributes\n\nSeverity: Critical\n\nRequired:\n\n* MUST NOT bind attacker-provided strings into event handler attributes (e.g., `onclick`, `onfocus`, etc.).\n* MUST treat “user-provided JS” as unsafe unless sandboxed and self-only exposure is guaranteed. ([Vue.js][1])\n\nInsecure patterns:\n\n* `<div :onclick=\"userProvidedString\">`\n* `<a :onmouseenter=\"userProvidedString\">`\n\nDetection hints:\n\n* Search: `:on` followed by event attribute names (`:onclick`, `:onload`, etc.).\n* Search for `setAttribute('on` patterns.\n\nFix:\n\n* Use real event listeners with developer-controlled handlers.\n* If you truly need user scripting, isolate it (sandboxed iframe + strict boundaries).\n\n---\n\n### VUE-ROUTER-001: Do not treat client-side route guards as authorization\n\nSeverity: High\n\nRequired:\n\n* MUST NOT rely on Vue Router guards, UI hiding, or client-side checks to enforce authorization.\n* MUST enforce authorization on the backend for every privileged action and sensitive data response. ([OWASP Cheat Sheet Series][8])\n\nInsecure patterns:\n\n* “Admin route is protected because `beforeEach` checks `user.isAdmin`.”\n* Sensitive API endpoints that assume “the frontend won’t call this unless allowed.”\n\nDetection hints:\n\n* Search `router.beforeEach` for role-based gating and see if the backend is also enforcing.\n* Look for “security by route meta” patterns (`meta.requiresAdmin`) with no server corroboration.\n\nFix:\n\n* Keep route guards as UX only (reduce accidental access), but enforce real checks server-side.\n\n---\n\n### VUE-ROUTER-002: Prevent open redirects and unsafe “return_to/next” handling\n\nSeverity: Low\n\nRequired:\n\n* MUST validate redirect destinations derived from untrusted input (`next`, `return_to`, `redirect`).\n* SHOULD allow only same-site relative paths or an explicit allowlist of destinations.\n* MUST NOT allow non `http` / `https` protos (such as `javascript:`)\n\nInsecure patterns:\n\n* `router.push(route.query.next as string)`\n* `window.location.href = route.query.redirect`\n\nDetection hints:\n\n* Search for `route.query.next`, `route.query.redirect`, `return_to`, `continue`, `callback`.\n* Trace the value into router/window navigation sinks.\n\nFix:\n\n* Allow only relative paths starting with `/` (and reject `//host`, `javascript:`, etc.).\n* Prefer redirecting to named routes you control.\n\nNotes:\n\n* Even Vue’s docs note that sanitized URLs still may not guarantee safe destinations. ([Vue.js][1])\n\n---\n\n### VUE-AUTH-001: Token storage must assume XSS is possible\n\nSeverity: Low\n\nRequired:\n\n* MUST assume any token accessible to JavaScript can be stolen via XSS.\n* SHOULD prefer HttpOnly cookies (set by the backend) for session tokens, combined with CSRF protections where relevant. ([Vue.js][1])\n* SHOULD avoid storing long-lived tokens (especially refresh tokens) in `localStorage`/`sessionStorage`.\n\nInsecure patterns:\n\n* `localStorage.setItem('token', ...)` for long-lived bearer tokens.\n* Storing refresh tokens in JS-accessible storage.\n\nDetection hints:\n\n* Search: `localStorage`, `sessionStorage`, `indexedDB`, `persist`, `pinia-plugin-persistedstate`.\n* Identify whether stored values are auth/session material.\n\nFix:\n\n* Prefer backend-managed sessions via HttpOnly cookies.\n* If bearer tokens are unavoidable, keep them short-lived, stored in memory, and rotate frequently; combine with strong XSS mitigations (CSP, Trusted Types, strict sanitization). ([OWASP Cheat Sheet Series][4])\n\n---\n\n### VUE-CSRF-001: Coordinate with the backend for CSRF when using cookies\n\nSeverity: High (for cookie-authenticated state-changing requests)\n\nNOTE: If the application is not using cookie based authentication (for example if it passes an Authorization header), then CSRF is not a concern\n\nRequired:\n\n* If API requests include cookies (`credentials: 'include'` / `withCredentials: true`) and cookies authenticate the user, MUST include CSRF protections coordinated with the backend (token/header patterns, Origin checks, SameSite cookies as defense-in-depth). ([Vue.js][1])\n* MUST NOT “solve CORS/CSRF errors” by disabling protections on the backend or using `mode: 'no-cors'` on the frontend.\n\nInsecure patterns:\n\n* `fetch(url, { credentials: 'include', method: 'POST', body: ... })` with no CSRF token/header usage anywhere.\n* Enabling cross-origin credentialed requests without strict origin allowlists (backend-side).\n\nDetection hints:\n\n* Search: `credentials: 'include'`, `withCredentials`, `xsrf`, `csrf`, `X-CSRF-Token`, `X-XSRF-TOKEN`.\n* Look at API wrapper modules for headers and cookie settings.\n\nFix:\n\n* Implement backend-issued CSRF tokens and require them on state-changing requests.\n* Keep cookies `SameSite=Lax/Strict` where compatible and verify Origin/Referer where appropriate (backend-driven). ([OWASP Cheat Sheet Series][9])\n\nNotes:\n\n* Vue’s docs explicitly say CSRF is primarily backend-addressed but recommends coordinating on CSRF token submission. ([Vue.js][1])\n\n---\n\n### VUE-HTTP-001: Do not put secrets in URLs; avoid leaking sensitive data in navigation/logs\n\nSeverity: Medium\n\nRequired:\n\n* MUST NOT place tokens/secrets in query strings or fragments (they leak via logs, referrers, browser history).\n* SHOULD avoid logging sensitive values to console in production.\n\nInsecure patterns:\n\n* `/?token=...`, `/#access_token=...` used beyond short-lived OAuth handoff.\n* `console.log(userSession)` that includes tokens/PII.\n\nDetection hints:\n\n* Search for `token=` in router parsing, auth callback handlers, and analytics logs.\n* Search for `console.log(` around auth code.\n\nFix:\n\n* Use Authorization headers or HttpOnly cookies.\n* Scrub logs; gate debug logs behind dev-only checks.\n\n---\n\n### VUE-HEADERS-001: Require security headers at the deployment layer\n\nSeverity: Medium\n\nRequired:\n\n* SHOULD deploy a CSP (`Content-Security-Policy`) suitable for your Vue app.\n* SHOULD deploy clickjacking defenses (CSP `frame-ancestors` and/or `X-Frame-Options`) unless intentional embedding is required.\n* SHOULD deploy `X-Content-Type-Options: nosniff`, plus other headers as appropriate (Referrer-Policy, Permissions-Policy). ([OWASP Cheat Sheet Series][4])\n\nInsecure patterns:\n\n* No evidence of headers in server/CDN config for an app with UGC or rich HTML rendering.\n* CSP includes `unsafe-inline`/`unsafe-eval` without strong justification.\n\nDetection hints:\n\n* Look for hosting config: nginx, Netlify/Vercel headers config, CloudFront/Cloudflare rules.\n* If absent in repo, flag as “verify at edge”.\n\nFix:\n\n* Set headers at the edge or in the server. Start with a conservative CSP and tighten.\n\n---\n\n### VUE-CSP-001: Use Trusted Types and DOM XSS hardening when feasible\n\nSeverity: Low\n\nRequired:\n\n* For apps with significant DOM injection surface (rich text, plugins, `v-html`), SHOULD consider enabling Trusted Types to reduce DOM XSS risk. ([web.dev][10])\n* SHOULD treat Trusted Types as defense-in-depth, not a replacement for sanitization.\n\nInsecure patterns:\n\n* Frequent use of `innerHTML`/`v-html` without sanitization or CSP hardening.\n\nDetection hints:\n\n* Search: `v-html`, `innerHTML`, `insertAdjacentHTML`.\n* Check CSP for `require-trusted-types-for 'script'` usage (if headers are in repo).\n\nFix:\n\n* Reduce/centralize HTML injection, sanitize inputs, and add Trusted Types policies where appropriate.\n\n---\n\n### VUE-THIRDPARTY-001: Avoid dynamic third-party script injection; prefer static, vetted loading\n\nSeverity: Low\n\nRequired:\n\n* MUST NOT inject `<script src=\"...\">` where the URL is user-controlled.\n* SHOULD treat third-party widgets/analytics as supply-chain risk; load only from vetted, pinned sources.\n\nInsecure patterns:\n\n* `const s=document.createElement('script'); s.src = userProvidedUrl; ...`\n* “Plugin marketplace” that loads arbitrary remote scripts.\n\nDetection hints:\n\n* Search: `createElement('script')`, `.src =`, `appendChild(script)`.\n* Search for “loadExternalScript”, “injectScript”, “cdnUrl”.\n\nFix:\n\n* Bundle dependencies, or allowlist strict origins and enforce integrity (see SRI rule).\n* Consider sandboxed iframes for untrusted third-party UI.\n\n---\n\n### VUE-SRI-001: Use Subresource Integrity for CDN-hosted scripts/styles\n\nSeverity: Low\n\nRequired:\n\n* If loading scripts/styles from a CDN, SHOULD use Subresource Integrity (`integrity` attribute) with appropriate `crossorigin` configuration. ([MDN Web Docs][11])\n* SHOULD prefer self-hosting or bundling over runtime CDN dependencies for security-critical code.\n\nInsecure patterns:\n\n* `<script src=\"https://cdn.example/...\">` with no `integrity`.\n* Remote script URLs that can change content without version pinning.\n\nDetection hints:\n\n* Search `index.html` and server templates for `https://` script/style tags.\n* Check for `integrity=`.\n\nFix:\n\n* Add SRI hashes (and pin versions), or bundle assets with your build.\n\n---\n\n### VUE-SUPPLY-001: Dependency and patch hygiene is mandatory\n\nSeverity: Low\n\nRequired:\n\n* SHOULD keep Vue and official companion libraries updated; Vue explicitly recommends using latest versions to remain as secure as possible. ([Vue.js][1])\n* MUST respond to security advisories promptly.\n* SHOULD pin dependencies and keep lockfiles committed (to reduce drift in production artifacts).\n\nInsecure patterns:\n\n* Outdated major versions with known CVEs.\n* No lockfile in repo; wide semver ranges for critical deps.\n* Ignoring advisories for template/rendering/compiler packages.\n\nDetection hints:\n\n* Inspect `package.json`, lockfiles, CI install commands.\n* Search for `npm audit` disabled, “ignore vulnerabilities” scripts.\n\nFix:\n\n* Upgrade dependencies and add regression tests around the impacted behavior.\n* Add dependency scanning in CI.\n\n---\n\n### VUE-SSR-001: SSR adds additional trust boundaries; treat state injection as XSS-sensitive\n\nSeverity: Medium\n\nRequired:\n\n* When using SSR, MUST treat anything injected into the HTML document (initial state, serialized data, inline scripts) as XSS-sensitive.\n* MUST keep the “trusted templates only” rule even stricter, because unsafe templates can lead to server-side execution during rendering. ([Vue.js][1])\n* SHOULD follow Vue SSR documentation and best practices for SSR security. ([Vue.js][1])\n\nInsecure patterns:\n\n* Concatenating untrusted strings into SSR templates.\n* Injecting JSON into `<script>` blocks without robust escaping/serialization controls.\n\nDetection hints:\n\n* Search server code for `__INITIAL_STATE__`, `window.__*STATE__`, template concatenation, and SSR render pipelines.\n* Trace untrusted data into those sinks.\n\nFix:\n\n* Use safe serialization patterns recommended by your SSR stack.\n* Avoid rendering untrusted HTML; sanitize or isolate.\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* Dev/preview servers in production:\n\n  * `npm run dev`, `vite`, `vite preview`, `vue-cli-service serve` ([vitejs][5])\n* Secrets exposure:\n\n  * `.env`, `.env.production`, `.env.*.local`, `VITE_`, `import.meta.env`, hard-coded `API_KEY` / `SECRET` ([vitejs][2])\n* XSS sinks:\n\n  * `v-html`, `innerHTML`, `insertAdjacentHTML`, `DOMParser`, `document.write` ([Vue.js][1])\n* Client-side template injection:\n\n  * `template:` concatenation, `compile(`, runtime compiler usage, mounting on non-sterile DOM ([Vue.js][1])\n* URL injection / open redirects:\n\n  * `:href=\"...\"` / `:src=\"...\"` from user data\n  * `javascript:` occurrences\n  * `route.query.next` / `redirect` / `return_to` flowing into `router.push` or `window.location` ([Vue.js][1])\n* Style injection:\n\n  * `:style=\"userProvidedStyles\"` or user-driven theme CSS ([Vue.js][1])\n* Token storage:\n\n  * `localStorage.setItem('token'...)`, persisted auth stores, refresh tokens in JS-accessible storage\n* CSRF integration red flags:\n\n  * `credentials: 'include'` / `withCredentials: true` without any CSRF header/token handling ([Vue.js][1])\n* Third-party scripts:\n\n  * dynamic script injection (`createElement('script')`), CDN scripts without SRI ([MDN Web Docs][11])\n* External links security:\n\n  * `target=\"_blank\"` without `rel=\"noopener\"`/`noreferrer` (still recommended for legacy and explicitness) ([MDN Web Docs][12])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (HTML/DOM insertion, template compilation, URL navigation, style injection, script injection)\n* protective controls present (sanitization, allowlists, CSP/Trusted Types, backend validation)\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary Vue documentation:\n\n* Vue Docs: Security — `https://vuejs.org/guide/best-practices/security` ([Vue.js][1])\n* Vue Docs: Template Syntax (security warning about in-DOM templates) — `https://vuejs.org/guide/essentials/template-syntax` ([Vue.js][13])\n* Vue Docs: Production Deployment — `https://vuejs.org/guide/best-practices/production-deployment` ([Vue.js][3])\n* Vue Docs: Feature Flags — `https://link.vuejs.org/feature-flags` ([Vue.js][7])\n\nVite documentation (common Vue tooling):\n\n* Vite Docs: Env Variables and Modes (VITE_* exposure + security notes) — `https://vite.dev/guide/env-and-mode` ([vitejs][2])\n* Vite Docs: CLI (`vite preview` not designed for production) — `https://vite.dev/guide/cli` ([vitejs][5])\n* Vite Docs: Server Options (`server.host` can listen on public addresses) — `https://vite.dev/config/server-options` ([vitejs][14])\n\nOWASP and web platform hardening references:\n\n* OWASP Cheat Sheet Series: XSS Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html` ([Vue.js][1])\n* OWASP Cheat Sheet Series: CSRF Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][9])\n* OWASP Cheat Sheet Series: Authorization — `https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][8])\n* OWASP Cheat Sheet Series: HTTP Headers — `https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][4])\n* HTML5 Security Cheat Sheet (referenced by Vue) — `https://html5sec.org/` ([Vue.js][1])\n\nBrowser/platform references:\n\n* MDN: `rel=\"noopener\"` — `https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/noopener` ([MDN Web Docs][12])\n* MDN: Subresource Integrity — `https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity` ([MDN Web Docs][11])\n* web.dev: Trusted Types — `https://web.dev/trusted-types/` ([web.dev][10])\n\n[1]: https://vuejs.org/guide/best-practices/security \"https://vuejs.org/guide/best-practices/security\"\n[2]: https://vite.dev/guide/env-and-mode \"https://vite.dev/guide/env-and-mode\"\n[3]: https://vuejs.org/guide/best-practices/production-deployment \"https://vuejs.org/guide/best-practices/production-deployment\"\n[4]: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html\"\n[5]: https://vite.dev/guide/cli \"https://vite.dev/guide/cli\"\n[6]: https://vite.dev/guide/build \"https://vite.dev/guide/build\"\n[7]: https://vuejs.org/guide/best-practices/production-deployment?utm_source=chatgpt.com \"Production Deployment\"\n[8]: https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html\"\n[9]: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html\"\n[10]: https://web.dev/articles/trusted-types \"https://web.dev/articles/trusted-types\"\n[11]: https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity?utm_source=chatgpt.com \"Subresource Integrity - Security - MDN Web Docs\"\n[12]: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/noopener \"https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/noopener\"\n[13]: https://vuejs.org/guide/essentials/template-syntax \"Template Syntax | Vue.js\"\n[14]: https://vite.dev/config/server-options \"https://vite.dev/config/server-options\"\n\n<!-- File: core/skills/builtin/security-best-practices/references/python-django-web-server-security.md (Tokens: ~8837 | Category: anthropic-skill) -->\n# Django (Python) Web Security Spec (Django 6.0.x, Python 3.x)\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new Django code.\n2. **Security review / vulnerability hunting** in existing Django code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session cookies, `SECRET_KEY`, `SECRET_KEY_FALLBACKS`, database passwords).\n* MUST NOT “fix” security by disabling protections (e.g., removing `CsrfViewMiddleware`, sprinkling `@csrf_exempt`, loosening `ALLOWED_HOSTS` to `['*']`, disabling `SecurityMiddleware`, disabling template auto-escaping, disabling permission checks).\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and concrete configuration values that justify the claim.\n* MUST treat uncertainty honestly: if a protection might exist in infrastructure (reverse proxy, WAF, CDN, ingress controller), report it as “not visible in app code; verify at runtime / edge config”.\n* MUST keep fixes compatible with Django’s intended security model: prefer Django’s built-ins (middleware, auth, forms, ORM) over custom security logic whenever possible. Django’s deployment checklist and system checks are part of the intended model. ([Django Project][1])\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new Django code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default Django APIs and proven libraries over custom security code.\n* MUST avoid introducing new risky sinks (dynamic template rendering from untrusted strings, unsafe redirects, unsafe file serving, shell execution, raw SQL string formatting, SSRF-capable URL fetchers from untrusted input).\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a Django repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. Deployment entrypoints (ASGI/WSGI), Dockerfiles, Procfiles, systemd units, platform manifests.\n2. `settings.py` and environment-specific settings modules.\n3. Middleware ordering and enabled protections.\n4. Authn/authz (login, session management, permissions, admin).\n5. CSRF protections and state-changing endpoints.\n6. Templates and XSS.\n7. File handling (uploads/downloads/static/media) and path traversal.\n8. Injection classes (SQL, command execution, unsafe deserialization).\n9. Outbound requests (SSRF).\n10. Redirect handling (open redirects) + CORS + security headers (CSP, HSTS, etc.).\n11. Dependency/pinning and patch posture.\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nExamples include:\n\n* `request.GET`, `request.POST`, `request.FILES`\n* `request.body`, JSON bodies (e.g., `json.loads(request.body)`), DRF `request.data`\n* URL path parameters (e.g., `<int:id>`, `<slug:...>`)\n* `request.headers` / `request.META` (including `HTTP_HOST`, `HTTP_ORIGIN`, `HTTP_REFERER`, `HTTP_X_FORWARDED_*`)\n* `request.COOKIES`\n* Any data from external systems (webhooks, third-party APIs, message queues)\n* Any persisted content that originated from users (DB rows, cached content, file uploads)\n\nDjango explicitly emphasizes “never trust user-controlled data” and recommends using forms/validation. ([Django Project][2])\n\n### 2.2 State-changing request\n\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook send), or initiate privileged actions.\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + function/class/view name + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common Django misconfigurations. Django provides a “Deployment checklist” and recommends running `manage.py check --deploy` against production settings. ([Django Project][1])\n\n### 3.1 Settings management pattern (SHOULD)\n\n* SHOULD use environment-based configuration (or a secret manager) so production settings are not hard-coded.\n* MUST treat sensitive settings as confidential (e.g., `SECRET_KEY`, DB passwords) and keep them out of source control. Django’s checklist explicitly recommends loading `SECRET_KEY` from env or a file rather than hardcoding. ([Django Project][1])\n* SHOULD separate dev vs prod settings modules, with safe defaults for production (fail closed if critical settings are missing). ([Django Project][1])\n\n### 3.2 Minimum baseline targets (production)\n\n* MUST NOT use `manage.py runserver` as the production entrypoint; use a production-ready WSGI or ASGI server. ([Django Project][1])\n* MUST set `DEBUG = False` in production. ([Django Project][1])\n* MUST set a strong, secret `SECRET_KEY` and keep it secret; MAY use `SECRET_KEY_FALLBACKS` for safe rotation. ([Django Project][1])\n* MUST set `ALLOWED_HOSTS` to expected hosts (no wildcard unless you do your own host validation). ([Django Project][1])\n* MUST enforce HTTPS for authenticated areas (ideally site-wide for any login-capable app) and set `CSRF_COOKIE_SECURE=True` and `SESSION_COOKIE_SECURE=True` when HTTPS is used. ([Django Project][1])\n* SHOULD enable key `SecurityMiddleware` headers/settings: HSTS, Referrer-Policy, COOP, nosniff, SSL redirect (with correct proxy configuration). ([Django Project][3])\n* MUST treat user uploads as untrusted; ensure your web server never interprets them as executable content; keep `MEDIA_ROOT` separate from `STATIC_ROOT`. ([Django Project][1])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### DJANGO-DEPLOY-001: Do not use Django’s development server in production\n\nSeverity: High (if production)\n\nRequired:\n\n* MUST NOT deploy `manage.py runserver` as the production server.\n* MUST run behind a production-grade WSGI or ASGI server. ([Django Project][1])\n\nInsecure patterns:\n\n* Production docs/scripts using `python manage.py runserver 0.0.0.0:8000`.\n* Docker `CMD`/entrypoint uses `runserver`.\n* Kubernetes/Procfile/systemd units invoking `runserver`.\n\nDetection hints:\n\n* Search for `manage.py runserver`, `runserver 0.0.0.0`, `--insecure`.\n* Check Docker `CMD/ENTRYPOINT`, Procfile, systemd unit files, Helm charts.\n\nFix:\n\n* Use a production server (WSGI/ASGI) as recommended in Django’s deployment checklist. ([Django Project][1])\n\nNote:\n\n* `runserver` is fine for local development. Only flag if it’s used as the production entrypoint.\n\n---\n\n### DJANGO-DEPLOY-002: `DEBUG` MUST be disabled in production\n\nSeverity: High\n\nRequired:\n\n* MUST set `DEBUG = False` in production.\n* MUST treat any mechanism that exposes debug pages/tracebacks to untrusted users as a critical information disclosure risk. Django’s checklist explicitly warns `DEBUG=True` leaks source excerpts, local variables, settings, and more. ([Django Project][1])\n\nInsecure patterns:\n\n* `DEBUG = True` in production settings.\n* Environment defaults to `DEBUG=True` unless explicitly overridden.\n\nDetection hints:\n\n* Search `DEBUG = True`, `DEBUG=os.environ.get(..., True)`, `DJANGO_DEBUG`, `.env` files.\n* Look for “production” settings modules that import from dev defaults.\n\nFix:\n\n* Set `DEBUG=False` in prod settings; use explicit environment config.\n* Ensure error reporting is via safe logging/monitoring, not debug pages. ([Django Project][1])\n\n---\n\n### DJANGO-CONFIG-001: `SECRET_KEY` must be strong, secret, and rotated safely\n\nSeverity: High (Critical if missing in production with signing/sessions)\n\nRequired:\n\n* MUST set a large random `SECRET_KEY` in production and keep it secret. ([Django Project][1])\n* MUST NOT commit it to source control or print/log it. ([Django Project][1])\n* SHOULD load it from env or a file/secret store (not hard-coded). ([Django Project][1])\n* MAY rotate keys using `SECRET_KEY_FALLBACKS` to avoid instantly invalidating all signed data; MUST remove old keys from fallbacks in a timely manner. ([Django Project][1])\n\nInsecure patterns:\n\n* Hard-coded `SECRET_KEY = \"...\"` in repo for production.\n* `SECRET_KEY` reused across environments.\n* `SECRET_KEY_FALLBACKS` contains long-expired keys indefinitely.\n\nDetection hints:\n\n* Search for `SECRET_KEY =`, `SECRET_KEY_FALLBACKS`, `.env` committed files, `print(settings.SECRET_KEY)`.\n\nFix:\n\n* Load from secret manager / environment variable.\n* If rotating:\n\n  * Set new `SECRET_KEY`\n  * Keep old key(s) temporarily in `SECRET_KEY_FALLBACKS`\n  * Remove old key(s) after the rotation window. ([Django Project][1])\n\n---\n\n### DJANGO-HOST-001: Host header must be validated (`ALLOWED_HOSTS` must be strict)\n\nSeverity: Medium\n\nRequired:\n\n* MUST set `ALLOWED_HOSTS` in production to your expected domains/hosts. ([Django Project][1])\n* MUST NOT set `ALLOWED_HOSTS = ['*']` in production unless you also implement your own robust `Host` validation (Django warns that wildcards require your own validation to avoid CSRF-class attacks). ([Django Project][1])\n* SHOULD configure the fronting web server to reject unknown hosts early (defense-in-depth). ([Django Project][1])\n\nInsecure patterns:\n\n* `ALLOWED_HOSTS = ['*']` (or env expands to `*`) in production.\n* `ALLOWED_HOSTS = []` with `DEBUG=False` (site won’t run, or misconfigured deployments attempt workarounds).\n\nDetection hints:\n\n* Search `ALLOWED_HOSTS`.\n* Check platform environment settings that override `ALLOWED_HOSTS`.\n\nFix:\n\n* Set `ALLOWED_HOSTS = ['example.com', 'www.example.com', ...]` for prod.\n* Keep dev hosts separate.\n\nNotes:\n\n* Django uses the Host header for URL construction; fake Host values can lead to CSRF, cache poisoning, and poisoned email links (Django security docs call this out). ([Django Project][2])\n\n---\n\n### DJANGO-HTTPS-001: If TLS is used cookie transport must be secured\n\nSeverity: High (Critical for auth-enabled apps)\n\nNOTE: Only enforce this if TLS is enabled, as it will break non-TLS applications\n\nIf using TLS:\n* MUST set:\n\n  * `CSRF_COOKIE_SECURE = True` ([Django Project][1])\n  * `SESSION_COOKIE_SECURE = True` ([Django Project][1])\n* SHOULD consider enabling:\n\n  * `SECURE_SSL_REDIRECT = True` (with correct proxy config) ([Django Project][3])\n  * HSTS via `SECURE_HSTS_SECONDS` (+ includeSubDomains/preload as appropriate). ([Django Project][3])\n\nInsecure patterns:\n\n* Login pages over HTTP, or mixed HTTP/HTTPS with the same session cookie.\n* `CSRF_COOKIE_SECURE=False` or `SESSION_COOKIE_SECURE=False` in production HTTPS.\n* HSTS enabled incorrectly (can break site for the duration).\n\nDetection hints:\n\n* Inspect `settings.py` for `CSRF_COOKIE_SECURE`, `SESSION_COOKIE_SECURE`, `SECURE_SSL_REDIRECT`, `SECURE_HSTS_SECONDS`.\n* Inspect proxy/ingress config for HTTP->HTTPS redirect behavior.\n\nFix:\n\n* Enable HTTPS redirect and secure cookies.\n* Add HSTS carefully (start with low value, validate, then increase). Django warns misconfig can break your site for the HSTS duration. ([Django Project][3])\n\n---\n\n### DJANGO-PROXY-001: Reverse proxy trust must be configured correctly (`SECURE_PROXY_SSL_HEADER`)\n\nSeverity: Medium (when behind a TLS proxy)\n\nRequired:\n\n* If behind a reverse proxy that terminates TLS, MUST configure Django so `request.is_secure()` reflects the *external* scheme, otherwise CSRF and other logic can break. Django documents using `SECURE_PROXY_SSL_HEADER` for this. ([Django Project][3])\n* MUST only set `SECURE_PROXY_SSL_HEADER` if you control the proxy (or have guarantees) and it strips inbound spoofed headers. Django explicitly warns misconfig can compromise security and lists required conditions. ([Django Project][3])\n\nInsecure patterns:\n\n* `SECURE_PROXY_SSL_HEADER = (\"HTTP_X_FORWARDED_PROTO\", \"https\")` in an environment where the proxy does not strip user-supplied `X-Forwarded-Proto`.\n* Infinite redirect loops after setting `SECURE_SSL_REDIRECT=True` (often indicates proxy HTTPS detection is wrong). ([Django Project][3])\n\nDetection hints:\n\n* Search `SECURE_PROXY_SSL_HEADER`, `SECURE_SSL_REDIRECT`.\n* Inspect ingress/proxy behavior for stripping forwarded headers.\n\nFix:\n\n* Set `SECURE_PROXY_SSL_HEADER` only if the proxy strips and sets the header correctly (per Django’s documented prerequisites). ([Django Project][3])\n\n---\n\n### DJANGO-SESS-001: Session cookies must use secure attributes in production\n\nSeverity: Medium (Only if TLS enabled)\n\nRequired (production, HTTPS):\n\n* MUST set `SESSION_COOKIE_SECURE=True` (only transmit over HTTPS). ([Django Project][3])\n* MUST keep `SESSION_COOKIE_HTTPONLY=True` (Django default is `True`). ([Django Project][3])\n* SHOULD keep `SESSION_COOKIE_SAMESITE='Lax'` (Django default is `Lax`) unless a justified cross-site flow requires `None`. ([Django Project][3])\n* SHOULD avoid setting `SESSION_COOKIE_DOMAIN` unless you truly need cross-subdomain cookies (subdomain-wide cookies expand attack surface).\n\nInsecure patterns:\n\n* `SESSION_COOKIE_SECURE=False` in production HTTPS.\n\nIMPORTANT NOTE: Only set `Secure` in production environment when TLS is configured. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n\n* `SESSION_COOKIE_HTTPONLY=False`.\n* `SESSION_COOKIE_SAMESITE=None` combined with cookie-authenticated state-changing endpoints (higher CSRF risk).\n\nDetection hints:\n\n* Search for `SESSION_COOKIE_` settings, `response.set_cookie(..., httponly=..., secure=..., samesite=...)`.\n\nFix:\n\n* Set the above explicitly in production settings.\n* Validate compatibility with your auth flows. ([Django Project][3])\n\n---\n\n### DJANGO-SESS-002: CSRF cookie settings must be deliberate (HttpOnly has tradeoffs)\n\nSeverity: Medium\n\nRequired:\n\n* SHOULD set `CSRF_COOKIE_SECURE=True` when using HTTPS/TLS. ([Django Project][3])\n* SHOULD keep `CSRF_COOKIE_SAMESITE='Lax'` unless you have a cross-site requirement. Django default is `Lax`. ([Django Project][3])\n* MAY set `CSRF_COOKIE_HTTPONLY=True` (default is `False`) if your frontend does not need to read the CSRF cookie. If you enable it, your JS must read the CSRF token from the DOM instead (Django documents this). ([Django Project][3])\n\nInsecure patterns:\n\n* `CSRF_COOKIE_SECURE=False` in production HTTPS/TLS.\n* Setting `CSRF_COOKIE_HTTPONLY=True` but still relying on “read csrftoken cookie in JS” patterns (breaks CSRF for AJAX).\n* `CSRF_COOKIE_SAMESITE=None` without a clear reason.\n\nDetection hints:\n\n* Search for `CSRF_COOKIE_` settings.\n* Search JS for `document.cookie` usage to fetch `csrftoken`.\n\nFix:\n\n* Align cookie settings with your CSRF token acquisition method (cookie vs DOM) as Django describes. ([Django Project][4])\n\n---\n\n### DJANGO-CSRF-001: Cookie-authenticated state-changing requests MUST be CSRF-protected\n\nSeverity: High\n\nRequired:\n\n* MUST keep `django.middleware.csrf.CsrfViewMiddleware` enabled (it is activated by default). ([Django Project][4])\n* MUST include `{% csrf_token %}` in internal POST forms; MUST NOT include it in forms that POST to external URLs (Django warns this leaks the token). ([Django Project][4])\n* MUST protect all state-changing endpoints (POST/PUT/PATCH/DELETE) that rely on cookies for authentication.\n* For AJAX/SPA calls, MUST send the CSRF token via the `X-CSRFToken` header (or configured header name) as documented. ([Django Project][4])\n* MUST be very careful with `@csrf_exempt` and use it only when absolutely necessary; if used, MUST replace CSRF with an appropriate alternative control (e.g., request signing for webhooks). Django explicitly warns about `csrf_exempt`. ([Django Project][2])\n\nInsecure patterns:\n\n* Missing `CsrfViewMiddleware` in `MIDDLEWARE`.\n* `@csrf_exempt` on general-purpose authenticated views.\n* POST/PUT/PATCH/DELETE endpoints with session auth and no CSRF tokens.\n* Using GET for state-changing actions (amplifies CSRF risk).\n\nDetection hints:\n\n* Inspect `settings.py` `MIDDLEWARE` for `CsrfViewMiddleware` and its order (Django notes it should come before middleware that assumes CSRF is handled). ([Django Project][4])\n* Search for `csrf_exempt`, `csrf_protect`, `ensure_csrf_cookie`.\n* Enumerate URL patterns for non-GET methods; confirm CSRF coverage.\n\nFix:\n\n* Re-enable `CsrfViewMiddleware`, add CSRF tokens to forms, and add AJAX header handling.\n* For caching decorators: if you cache a view that needs CSRF tokens, apply `@csrf_protect` as Django documents to avoid caching a response without CSRF cookie/Vary headers. ([Django Project][4])\n\nNotes:\n\n* When deployed with HTTPS, Django’s CSRF middleware also checks the Referer header for same-origin (Django security docs mention this). ([Django Project][2])\n\n---\n\n### DJANGO-XSS-001: Prevent reflected/stored XSS in templates and HTML generation\n\nSeverity: High\n\nRequired:\n\n* MUST rely on Django template auto-escaping (safe-by-default) for HTML templates. Django security docs highlight that Django templates escape dangerous characters but have limitations. ([Django Project][2])\n* MUST NOT disable auto-escaping broadly (`{% autoescape off %}`) unless the content is trusted or safely sanitized. ([Django Project][5])\n* MUST NOT mark untrusted content as safe:\n\n  * Avoid `mark_safe(...)` on user data.\n  * Avoid `|safe` on user-controlled content.\n* MUST be careful about HTML context pitfalls (e.g., unquoted attributes); Django explicitly shows an example where escaping does not protect an unquoted attribute context. ([Django Project][2])\n* SHOULD prefer safe HTML construction helpers (e.g., `format_html`) rather than manual concatenation that risks missing escapes. ([Django Project][6])\n\nInsecure patterns:\n\n* `{% autoescape off %}{{ user_input }}{% endautoescape %}`\n* `{{ user_input|safe }}`\n* `mark_safe(request.GET[\"q\"])`\n* Unquoted attribute injections: `<style class={{ var }}>...` (Django’s own example). ([Django Project][2])\n\nDetection hints:\n\n* Search templates for `|safe`, `autoescape off`, `safeseq`.\n* Search Python for `mark_safe`, `SafeString`, or direct HTML concatenation with request/DB values.\n* Review any code returning `HttpResponse(user_value)` where `user_value` contains HTML.\n\nFix:\n\n* Remove unsafe marking; sanitize only when strictly necessary (use an allowlist-based HTML sanitizer).\n* Quote attributes and avoid placing untrusted values into dangerous contexts.\n* Add CSP as defense-in-depth (see DJANGO-CSP-001). ([Django Project][2])\n\n---\n\n### DJANGO-TEMPLATE-001: Never render untrusted template source strings\n\nSeverity: High to Critical (depends on context and exposure)\n\nRequired:\n\n* MUST NOT render templates where the template source string is influenced by untrusted input (request, user content, DB rows editable by untrusted users).\n* MUST treat “template from string” patterns as dangerous, even if Django templates are more constrained than some other engines: they can still leak data from context, bypass escaping, and create XSS or content injection.\n\nInsecure patterns:\n\n* `Template(request.GET[\"tmpl\"]).render(Context(...))`\n* Saving user templates in the DB and rendering them with normal privileges/context.\n\nDetection hints:\n\n* Search for `django.template.Template(`, `Engine.from_string`, `.render(Context(` with non-constant strings.\n* Trace where the template string comes from (admin panels, DB, uploads, requests).\n\nFix:\n\n* Replace with non-executing formatting (e.g., `string.Template`, explicit placeholders) or a strict allowlisted rendering model.\n* If you *must* support user-defined templates, isolate heavily (separate service/tenant context, strict allowlists, and assume bypasses are possible).\n\n---\n\n### DJANGO-SQL-001: Prevent SQL injection (use ORM or parameterized raw SQL)\n\nSeverity: High\n\nRequired:\n\n* MUST use Django ORM/querysets for normal DB access; Django notes querysets are parameterized and protected from SQL injection under typical use. ([Django Project][2])\n* MUST be very careful with raw SQL; if using `raw()`, `cursor.execute()`, `extra()`, or `RawSQL`, MUST pass parameters separately (e.g., `params=`) and MUST NOT string-interpolate untrusted input into SQL. Django’s raw SQL docs warn to escape user-controlled parameters using `params`. ([Django Project][7])\n* MUST NOT quote placeholders in SQL templates (Django docs explicitly warn that quoting `%s` placeholders makes it unsafe). ([Django Project][8])\n* SHOULD avoid `extra()` and `RawSQL` unless necessary; Django security docs call for caution. ([Django Project][2])\n\nInsecure patterns:\n\n* `cursor.execute(f\"SELECT ... WHERE id={request.GET['id']}\")`\n* `Model.objects.raw(\"... %s\" % user_input)` (string formatting)\n* `extra(where=[f\"headline='{q}'\"])`\n* Quoted placeholders: `WHERE othercol = '%s'` (explicitly documented as unsafe). ([Django Project][8])\n\nDetection hints:\n\n* Grep for `.raw(`, `.extra(`, `RawSQL(`, `connection.cursor()`, `.execute(`.\n* Grep for SQL keywords (`SELECT`, `UPDATE`, `DELETE`, `INSERT`) in Python strings.\n* Track untrusted inputs into these call sites.\n\nFix:\n\n* Prefer ORM queries.\n* If raw SQL is unavoidable, use parameters (`params`, DB-API param binding) and do not quote placeholders. ([Django Project][7])\n\n---\n\n### DJANGO-CMD-001: Prevent OS command injection\n\nSeverity: Critical to High (depends on exposure)\n\nRequired:\n\n* MUST avoid executing system commands with attacker-influenced input.\n* If subprocess is necessary:\n\n  * MUST pass args as a list (not a shell string).\n  * MUST NOT use `shell=True` with attacker-influenced content.\n  * SHOULD use strict allowlists for variable components.\n* SHOULD prefer pure-Python libraries instead of shelling out.\n\nInsecure patterns:\n\n* `os.system(request.GET[\"cmd\"])`\n* `subprocess.run(f\"convert {path}\", shell=True)` where `path` is user-controlled.\n\nDetection hints:\n\n* Search `os.system`, `subprocess`, `Popen`, `shell=True`.\n* Trace request/DB inputs into those calls.\n\nFix:\n\n* Replace with library APIs; if unavoidable, hard-code executable and allowlist validated parameters.\n\n---\n\n### DJANGO-UPLOAD-001: File uploads must be validated, stored safely, and served safely\n\nSeverity: High\n\nRequired:\n\n* MUST treat all user uploads as untrusted. Django explicitly warns “Media files are uploaded by your users. They’re untrusted!” ([Django Project][1])\n* MUST ensure the web server never interprets user uploads as executable code (e.g., don’t allow uploaded `.php` or HTML to execute/inline as active content). ([Django Project][1])\n* MUST enforce size limits (at least at the web server; Django security docs recommend limiting upload size at the server to prevent DoS). ([Django Project][2])\n* SHOULD validate file types using allowlists and content checks (not only extensions).\n* SHOULD store uploads outside the application code directory and outside any static root.\n* SHOULD consider serving uploads from a separate top-level/second-level domain to reduce same-origin impact; Django security docs recommend a distinct domain and note that a subdomain may be insufficient for some protections. ([Django Project][2])\n* MUST be aware of polyglot upload risks: Django documents a case where HTML can be uploaded “as an image” by using a valid PNG header (and may be served as HTML depending on the web server). ([Django Project][2])\n\nInsecure patterns:\n\n* Serving uploads inline with `text/html` or without forcing download for potentially active formats.\n* Upload allowlist based only on extension.\n* Upload storage inside static roots or code roots.\n\nDetection hints:\n\n* Search for `request.FILES`, `FileField`, `ImageField`, upload forms/views.\n* Inspect upload serving paths and Nginx/Apache config (media handlers).\n* Check `MEDIA_URL`, `MEDIA_ROOT`, and static config.\n\nFix:\n\n* Configure the web server to serve uploads as inert bytes (no execution), and consider forcing `Content-Disposition: attachment` for risky types.\n* Use a separate domain for user content when warranted. ([Django Project][2])\n\n---\n\n### DJANGO-PATH-001: Prevent path traversal and unsafe file serving (static/media separation)\n\nSeverity: High\n\nRequired:\n\n* MUST NOT treat user input as a filesystem path for reads/writes/serving.\n* MUST keep `MEDIA_ROOT` and `STATIC_ROOT` distinct; Django settings docs explicitly warn they must have different values to avoid security implications. ([Django Project][3])\n* SHOULD prefer using Django storage APIs keyed by server-side identifiers rather than accepting arbitrary relative paths from users.\n\nInsecure patterns:\n\n* `open(os.path.join(MEDIA_ROOT, request.GET[\"path\"]))`\n* Download endpoints that take `?file=../../...` style parameters.\n* Misconfigured `MEDIA_ROOT == STATIC_ROOT`.\n\nDetection hints:\n\n* Grep for `open(`, `Path(`, `os.path.join(` used with request values.\n* Check `MEDIA_ROOT`, `STATIC_ROOT` in settings. ([Django Project][3])\n\nFix:\n\n* Use server-side IDs mapped to known files.\n* Keep static and media separated and ensure the web server treats media as untrusted. ([Django Project][3])\n\n---\n\n### DJANGO-REDIRECT-001: Prevent open redirects (`next`, `return_to`, `redirect`)\n\nSeverity: Medium (High when combined with auth flows)\n\nRequired:\n\n* MUST validate redirect targets derived from untrusted input (e.g., `next`, `return_to`).\n* SHOULD restrict to same-site relative paths or allowlisted hosts/schemes.\n* SHOULD use Django’s safe URL helpers (e.g., `django.utils.http.url_has_allowed_host_and_scheme`) rather than custom parsing.\n\nInsecure patterns:\n\n* `return redirect(request.GET.get(\"next\"))` with no validation.\n* Redirect allowlist implemented with naive string checks.\n\nDetection hints:\n\n* Search for `redirect(` and track origin of the target.\n* Search for parameters named `next`, `return_to`, `redirect`, `url`.\n\nFix:\n\n* Validate with allowlists and default to a safe internal path if validation fails.\n* Ensure host validation via `ALLOWED_HOSTS` remains strict (see DJANGO-HOST-001). ([Django Project][3])\n\n---\n\n### DJANGO-HEADERS-001: Enable essential security headers (SecurityMiddleware + clickjacking protection)\n\nSeverity: Medium to High\n\nRequired:\n\n* SHOULD use `django.middleware.security.SecurityMiddleware` and configure it appropriately (production) for:\n\n  * `X-Content-Type-Options: nosniff` (Django setting `SECURE_CONTENT_TYPE_NOSNIFF`, default `True`). ([Django Project][3])\n  * `Referrer-Policy` (Django setting `SECURE_REFERRER_POLICY`, default `'same-origin'`). ([Django Project][3])\n  * COOP (Django setting `SECURE_CROSS_ORIGIN_OPENER_POLICY`, default `'same-origin'`). ([Django Project][3])\n  * HTTPS redirects and HSTS as appropriate (see DJANGO-HTTPS-001). ([Django Project][3])\n* SHOULD enable clickjacking protection via X-Frame-Options middleware; Django security docs strongly recommend it for sites that don’t need third-party framing. ([Django Project][2])\n\nInsecure patterns:\n\n* Missing SecurityMiddleware.\n* Missing clickjacking protection (or disabling it globally) without a clear framing requirement.\n* Over-broad framing allowances for sensitive endpoints.\n\nDetection hints:\n\n* Inspect `MIDDLEWARE` for SecurityMiddleware and XFrameOptionsMiddleware.\n* Search for per-view disabling of framing/CSRF protections.\n\nFix:\n\n* Add/enable middleware and configure the settings intentionally. ([Django Project][3])\n\nNOTE:\n\n* Some headers may be set at the edge (CDN/reverse proxy). If not visible in app code, flag as “verify at edge”.\n\n---\n\n### DJANGO-CSP-001: Deploy a Content Security Policy (CSP) as defense-in-depth\n\nSeverity: Medium (High for apps rendering untrusted content)\n\nNOTE: It is most important to set the CSP's script-src. All other directives are not as important and can generally be excluded for the ease of development.\n\nRequired:\n\n* SHOULD deploy a CSP to mitigate XSS and content injection classes; Django’s security docs recommend CSP and note it is new in Django 6.0. ([Django Project][2])\n* MUST understand CSP limitations:\n\n  * Avoid excluding routes from CSP coverage; Django warns that an unprotected page can undermine protected pages due to same-origin policy. ([Django Project][2])\n* MAY start with `SECURE_CSP_REPORT_ONLY` to iterate safely (Django provides report-only support). ([Django Project][3])\n\nInsecure patterns:\n\n* No CSP on apps that render user-controlled content.\n* CSP excludes “just a couple pages” (weakens overall protection), especially pages with any injection surface. ([Django Project][2])\n* CSP uses overly permissive directives (e.g., widespread `unsafe-inline`) without justification.\n\nDetection hints:\n\n* Search `SECURE_CSP`, `SECURE_CSP_REPORT_ONLY`, and CSP middleware configuration.\n* Inspect reverse proxy/CDN config for CSP headers.\n\nFix:\n\n* Implement a realistic CSP, ideally report-only first, then enforce. ([Django Project][3])\n\n---\n\n### DJANGO-AUTH-001: Password storage must use Django’s secure hashers; password policy must be configured\n\nSeverity: High\n\nRequired:\n\n* MUST use Django’s built-in password hashing (never store plaintext or reversible encrypted passwords).\n* SHOULD prefer modern hashers and keep defaults updated; Django documents `PASSWORD_HASHERS` and includes modern options (Argon2, bcrypt, scrypt, PBKDF2 variants). ([Django Project][3])\n* SHOULD configure `AUTH_PASSWORD_VALIDATORS` (default is empty) for production password policy. ([Django Project][3])\n\nInsecure patterns:\n\n* Custom password storage or hashing.\n* Plaintext passwords stored in DB fields.\n* No password validation on consumer-facing apps.\n\nDetection hints:\n\n* Search for `.set_password(` usage vs manual hashing.\n* Inspect settings for `PASSWORD_HASHERS` and `AUTH_PASSWORD_VALIDATORS`. ([Django Project][3])\n\nFix:\n\n* Use Django auth user model APIs.\n* Enable password validators appropriate to the product’s risk profile. ([Django Project][3])\n\n---\n\n### DJANGO-AUTHZ-001: Authorization must be explicit and consistent\n\nSeverity: High\n\nRequired:\n\n* MUST enforce authorization checks on every privileged action (view, modify, admin-like operations).\n* MUST NOT rely on UI-only restrictions (e.g., hiding buttons) without server-side permission checks.\n* SHOULD use Django’s permissions/groups and per-object authorization patterns where applicable.\n\nInsecure patterns:\n\n* Views that assume “user is logged in” implies “user may do action”.\n* Missing authorization checks on update/delete endpoints.\n\nDetection hints:\n\n* Enumerate views that modify state; ensure they validate ownership/permission.\n* Look for use of only `is_authenticated` or only `is_staff` without checking object-level access.\n\nFix:\n\n* Add explicit permission checks and tests for unauthorized access.\n\n---\n\n### DJANGO-ADMIN-001: Django admin must be treated as a high-value target\n\nSeverity: High\n\nRequired:\n\n* MUST ensure admin is protected by strong authentication and HTTPS-only transport (see DJANGO-HTTPS-001). ([Django Project][1])\n* SHOULD restrict admin exposure (network allowlists, VPN, SSO, or additional authentication controls) when possible.\n* SHOULD audit installed admin extensions and third-party apps for XSS/CSRF exposure.\n\nInsecure patterns:\n\n* Admin exposed to the internet with weak authentication.\n* Admin served over HTTP.\n\nDetection hints:\n\n* Search `urlpatterns` for `admin.site.urls`.\n* Check deployment config for IP allowlisting or auth gateways.\n\nFix:\n\n* Add network controls and enforce HTTPS.\n\n---\n\n### DJANGO-LOG-001: Logging and error reporting must not leak secrets\n\nSeverity: Medium to High\n\nRequired:\n\n* MUST NOT log secrets (including `SECRET_KEY`, session cookies, auth headers, password reset tokens).\n* MUST configure production logging deliberately; Django’s deployment checklist explicitly calls out reviewing logging before production. ([Django Project][1])\n* MUST ensure `DEBUG=False` in production so exceptions aren’t rendered with sensitive context. ([Django Project][1])\n\nInsecure patterns:\n\n* Logging full request headers or cookies in production.\n* Printing settings dictionaries.\n* Debug error pages.\n\nDetection hints:\n\n* Inspect `LOGGING` config; search for middleware that logs request headers/cookies.\n* Grep for `print(settings` / `logging.info(request.META)` patterns.\n\nFix:\n\n* Redact sensitive values; log IDs not secrets.\n* Use structured logging and a safe error monitoring tool. ([Django Project][1])\n\n---\n\n### DJANGO-SUPPLY-001: Dependency and patch hygiene (Django + security-critical deps)\n\nSeverity: Medium (High if known vulnerable versions)\n\nRequired:\n\n* SHOULD pin and regularly update Django and security-critical dependencies.\n* MUST respond to Django security releases promptly.\n\nDetection hints:\n\n* Check `requirements.txt`, lockfiles, build images.\n* Identify Django version; compare against latest supported release (Django’s download page publishes current stable and supported branches). ([Django Project][9])\n\nFix:\n\n* Upgrade to patched versions; add regression tests for previously vulnerable classes.\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* Deployment/dev server:\n\n  * `manage.py runserver`, `runserver 0.0.0.0`, `--insecure` ([Django Project][1])\n* Debug / settings:\n\n  * `DEBUG = True` ([Django Project][1])\n  * `SECRET_KEY =`, `SECRET_KEY_FALLBACKS` ([Django Project][1])\n* Host validation:\n\n  * `ALLOWED_HOSTS = ['*']` ([Django Project][3])\n* HTTPS and proxy:\n\n  * `SECURE_SSL_REDIRECT`, `SECURE_HSTS_SECONDS`, `SECURE_PROXY_SSL_HEADER` ([Django Project][3])\n* Cookies / sessions:\n\n  * `SESSION_COOKIE_SECURE`, `SESSION_COOKIE_HTTPONLY`, `SESSION_COOKIE_SAMESITE` ([Django Project][3])\n  * `CSRF_COOKIE_SECURE`, `CSRF_COOKIE_HTTPONLY`, `CSRF_COOKIE_SAMESITE` ([Django Project][3])\n* CSRF bypasses:\n\n  * `csrf_exempt`, missing `CsrfViewMiddleware`, POST forms without `{% csrf_token %}` ([Django Project][4])\n* XSS:\n\n  * `|safe`, `autoescape off`, `mark_safe(`, HTML string concatenation ([Django Project][5])\n* SQL injection:\n\n  * `.raw(`, `.extra(`, `RawSQL(`, `cursor.execute(` with formatted SQL strings ([Django Project][7])\n* User uploads / media:\n\n  * `request.FILES`, `MEDIA_ROOT`, `MEDIA_URL`, serving media inline; `MEDIA_ROOT == STATIC_ROOT` ([Django Project][1])\n* Redirects:\n\n  * `redirect(request.GET.get(\"next\"))` patterns; missing allowlist validation\n* Security headers and CSP:\n\n  * Missing `SecurityMiddleware`, missing X-Frame-Options protection, missing `SECURE_CSP` adoption (where appropriate) ([Django Project][2])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (template/SQL/subprocess/files/redirect/http)\n* protective controls present (middleware, validation, allowlists, authz checks)\n* whether security headers/controls are set in-app vs at the edge\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary Django documentation:\n\n```text\n- Django Downloads (current stable & supported branches): https://www.djangoproject.com/download/\n- Django 6.0 Release Notes: https://docs.djangoproject.com/en/6.0/releases/6.0/\n- Django: Deployment checklist (incl. check --deploy, runserver warning, HTTPS/cookies guidance): https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/\n- Django: Settings reference (SecurityMiddleware settings, cookies, SECRET_KEY_FALLBACKS, CSP settings): https://docs.djangoproject.com/en/6.0/ref/settings/\n- Django: Security in Django (XSS/CSRF/SQLi/clickjacking/HTTPS/host header validation/uploads/CSP): https://docs.djangoproject.com/en/6.0/topics/security/\n- Django: CSRF how-to (middleware, csrf_token usage, AJAX header patterns, csrf_exempt cautions): https://docs.djangoproject.com/en/6.0/howto/csrf/\n- Django: Performing raw SQL queries (parameterization guidance): https://docs.djangoproject.com/en/6.0/topics/db/sql/\n- Django: QuerySet API reference (extra() cautions; “do not quote placeholders” guidance): https://docs.djangoproject.com/en/6.0/ref/models/querysets/\n- Django: Template built-ins (autoescape tag): https://docs.djangoproject.com/en/6.0/ref/templates/builtins/\n- Django: Template language reference (turning off autoescape & risks): https://docs.djangoproject.com/en/6.0/ref/templates/language/\n- Django: Utilities reference (e.g., format_html): https://docs.djangoproject.com/en/6.0/ref/utils/\n```\n\nOWASP:\n\n```text\n- OWASP Cheat Sheet Series: Django Security Cheat Sheet: https://cheatsheetseries.owasp.org/cheatsheets/Django_Security_Cheat_Sheet.html\n```\n\n[1]: https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/ \"https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/\"\n[2]: https://docs.djangoproject.com/en/6.0/topics/security/ \"Security in Django | Django documentation | Django\"\n[3]: https://docs.djangoproject.com/en/6.0/ref/settings/ \"Settings | Django documentation | Django\"\n[4]: https://docs.djangoproject.com/en/6.0/howto/csrf/ \"How to use Django’s CSRF protection | Django documentation | Django\"\n[5]: https://docs.djangoproject.com/en/6.0/ref/templates/builtins/ \"https://docs.djangoproject.com/en/6.0/ref/templates/builtins/\"\n[6]: https://docs.djangoproject.com/en/6.0/ref/utils/ \"https://docs.djangoproject.com/en/6.0/ref/utils/\"\n[7]: https://docs.djangoproject.com/en/6.0/topics/db/sql/ \"https://docs.djangoproject.com/en/6.0/topics/db/sql/\"\n[8]: https://docs.djangoproject.com/en/6.0/ref/models/querysets/ \"https://docs.djangoproject.com/en/6.0/ref/models/querysets/\"\n[9]: https://www.djangoproject.com/download/ \"Download Django | Django\"\n\n<!-- File: core/skills/builtin/security-best-practices/references/python-fastapi-web-server-security.md (Tokens: ~10420 | Category: anthropic-skill) -->\n# FastAPI (Python) Web Security Spec (FastAPI 0.128.x, Python 3.x) ([PyPI][1])\n\nThis document is designed as a **security spec** that supports:\n\n1. **Secure-by-default code generation** for new FastAPI code.\n2. **Security review / vulnerability hunting** in existing FastAPI code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\nFastAPI is commonly deployed with an ASGI server (e.g., Uvicorn) and is built on Starlette + Pydantic, so this spec covers those layers where they affect security. ([PyPI][1])\n\n---\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n* MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session cookies, signing keys, database URLs with credentials).\n* MUST NOT “fix” security by disabling protections (e.g., weakening auth, making CORS permissive, skipping signature checks, disabling validation, turning off TLS verification, adding `allow_origins=[\"*\"]` with credentials).\n* MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and configuration values that justify the claim.\n* MUST treat uncertainty honestly: if a protection might exist in infrastructure (reverse proxy, WAF, CDN, service mesh), report it as “not visible in app code; verify at runtime/config”.\n* MUST treat browser controls correctly:\n\n  * CORS is **not** an auth mechanism; it only affects browsers.\n  * CSRF defenses apply when the browser automatically attaches credentials (cookies); they are usually not relevant for purely header-token APIs. ([OWASP Cheat Sheet Series][2])\n\n---\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\n\nWhen asked to write new FastAPI code or modify existing code:\n\n* MUST follow every **MUST** requirement in this spec.\n* SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n* MUST prefer safe-by-default APIs and proven libraries over custom security code.\n* MUST avoid introducing new risky sinks (shell execution, unsafe deserialization, dynamic eval, untrusted template rendering, unsafe file serving, unsafe redirects, arbitrary outbound fetching).\n\n### 1.2 Passive review mode (always on while editing)\n\nWhile working anywhere in a FastAPI repo (even if the user did not ask for a security scan):\n\n* MUST “notice” violations of this spec in touched/nearby code.\n* SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\n\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n\n* MUST systematically search the codebase for violations of this spec.\n* MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n\n1. App entrypoints / deployment scripts / Dockerfiles / Procfiles / Helm/terraform.\n2. ASGI server configuration (Uvicorn/Gunicorn), proxy settings, debug/reload settings.\n3. FastAPI app configuration (docs exposure, middleware, trusted hosts, CORS).\n4. Authn/Authz design (dependencies, JWT/session handling, password storage).\n5. Cookie/session usage + CSRF (if cookies are used).\n6. Input validation and output shaping (Pydantic models, mass assignment, excessive data exposure).\n7. Template rendering and XSS/SSTI (if HTML is served).\n8. File handling (uploads + downloads), StaticFiles, Range support.\n9. Injection classes (SQL, command execution, unsafe deserialization).\n10. Outbound requests (SSRF), redirect handling, WebSockets security.\n\n---\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\n\nExamples include:\n\n* Query parameters / path parameters\n* JSON bodies (including nested fields)\n* Headers (including `Host`, `Origin`, `X-Forwarded-*`)\n* Cookies (including session cookies)\n* File uploads (multipart parts)\n* WebSocket messages, query params, and headers during handshake ([Starlette][3])\n* Any data from external systems (webhooks, third-party APIs, message queues)\n* Any persisted user content (DB rows) that originated from users\n\n### 2.2 State-changing request\n\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook send), or initiate privileged actions.\n\n### 2.3 Required audit finding format\n\nFor each issue found, output:\n\n* Rule ID:\n* Severity: Critical / High / Medium / Low\n* Location: file path + function/route name + line(s)\n* Evidence: the exact code/config snippet\n* Impact: what could go wrong, who can exploit it\n* Fix: safe change (prefer minimal diff)\n* Mitigation: defense-in-depth if immediate fix is hard\n* False positive notes: what to verify if uncertain\n\n---\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common FastAPI/ASGI misconfigurations.\n\nBaseline goals:\n\n* No debug tracebacks or auto-reload in production. ([PyPI][4])\n* Run under a production ASGI server configuration (workers, timeouts, resource controls). ([PyPI][4])\n* Host header validation enabled (TrustedHostMiddleware or equivalent). ([PyPI][5])\n* CORS disabled unless explicitly needed; if enabled, it is strict and least-privilege. ([OWASP Cheat Sheet Series][6])\n* Auth is enforced consistently via dependencies (no “oops, forgot auth on this route”). ([FastAPI][7])\n* If cookies/sessions are used, cookie flags are secure and CSRF is addressed. ([OWASP Cheat Sheet Series][8])\n* Request size limits and multipart limits exist at the edge and are validated in app as needed (to mitigate memory/CPU DoS). ([advisories.gitlab.com][9])\n* Dependencies are patched promptly, especially Starlette/python-multipart (multiple DoS and traversal advisories exist historically). ([advisories.gitlab.com][10])\n\n---\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### FASTAPI-DEPLOY-001: Do not use auto-reload / dev-only server modes in production\n\nSeverity: High (if production)\n\nRequired:\n\n* MUST NOT run production using auto-reload/watch mode (e.g., Uvicorn reload).\n* MUST run with a production process model (e.g., multiple workers where appropriate) and stable server settings. ([PyPI][4])\n\nInsecure patterns:\n\n* `uvicorn ... --reload` (or equivalent “reload=True” configs) in production entrypoints.\n* Docker/Procfile/systemd commands that run with `--reload` in production.\n\nDetection hints:\n\n* Search for `--reload`, `reload=True`, `watchfiles`, `fastapi dev`, “development” run scripts.\n* Check Docker CMD/ENTRYPOINT, Procfile, systemd units, shell scripts.\n\nFix:\n\n* Remove reload in production; run Uvicorn/Gunicorn with stable settings and explicit worker configuration. ([PyPI][4])\n\nNote:\n\n* Reload is fine for local development. Only flag when it is clearly used as a production entrypoint.\n\n---\n\n### FASTAPI-DEPLOY-002: Debug mode MUST be disabled in production\n\nSeverity: Critical\n\nRequired:\n\n* MUST NOT enable debug tracebacks in production (FastAPI/Starlette debug mode can expose sensitive internals and make some exploit chains easier). ([PyPI][5])\n* MUST treat any configuration that returns detailed stack traces to clients as sensitive.\n\nInsecure patterns:\n\n* `app = FastAPI(debug=True)` (or Starlette `debug=True`), or equivalent environment toggles enabling debug in production. ([PyPI][5])\n* Server/log config that exposes tracebacks to end users.\n\nDetection hints:\n\n* Search for `debug=True`, `DEBUG = True`, environment flags mapped to debug.\n* Review exception middleware and error handler setup.\n\nFix:\n\n* Ensure debug is only enabled in local dev/test.\n* Return generic error responses to clients; log details internally.\n\n---\n\n### FASTAPI-OPENAPI-001: OpenAPI and interactive docs MUST be disabled or protected in production\n\nSeverity: Medium (can be High in sensitive/internal apps)\n\nRequired:\n\n* SHOULD disable `/docs`, `/redoc`, and `/openapi.json` in production for public-facing services unless there is an explicit business need.\n* If enabled, MUST protect them (e.g., auth, network allowlists, or internal-only routing).\n* MUST NOT assume “security through obscurity”; treat docs exposure as an information disclosure amplifier.\n\nInsecure patterns:\n\n* Publicly reachable `/docs` and `/openapi.json` for internal/admin APIs.\n* Docs enabled on the same hostname as production without access control.\n\nDetection hints:\n\n* Look for `FastAPI(docs_url=..., redoc_url=..., openapi_url=...)` or defaults.\n* Check reverse proxy routing and allowlists.\n\nFix:\n\n* Disable docs endpoints in prod (`docs_url=None`, `redoc_url=None`, `openapi_url=None`) or restrict access at the edge.\n\n---\n\n### FASTAPI-AUTH-001: Authentication MUST be explicit and consistently enforced via dependencies\n\nSeverity: High\n\nRequired:\n\n* MUST implement authentication as a dependency (or router-level dependency) so that protected endpoints cannot “forget” auth.\n* MUST default to “deny” for privileged routers/endpoints; explicitly mark truly public routes.\n* SHOULD centralize auth enforcement at router boundaries (e.g., protected `APIRouter` for authenticated endpoints). ([FastAPI][7])\n\nInsecure patterns:\n\n* Per-route ad-hoc auth checks scattered through handlers (easy to miss).\n* A mix of protected/unprotected endpoints with no clear policy.\n\nDetection hints:\n\n* Identify routers and endpoints; check whether protected ones include `Depends(...)`/`Security(...)`.\n* Search for patterns like `if user is None: raise ...` inside handlers (instead of dependencies).\n\nFix:\n\n* Move authentication into a dependency and attach it to the router/endpoint consistently using `Depends()`/`Security()`. ([FastAPI][7])\n\n---\n\n### FASTAPI-AUTH-002: Use standard auth transports; avoid secrets in URLs\n\nSeverity: High\n\nRequired:\n\n* SHOULD use the `Authorization: Bearer <token>` header for token auth, not query parameters. ([FastAPI][11])\n* MUST NOT place secrets (tokens, reset links containing long-lived secrets, API keys) in query strings when avoidable.\n\nInsecure patterns:\n\n* `?token=...`, `?api_key=...`, `?auth=...` used for primary auth.\n* Long-lived access tokens embedded in URLs (leak via logs, referrers, caches).\n\nDetection hints:\n\n* Search for parameter names like `token`, `api_key`, `key`, `secret`, `password`.\n* Look for security schemes that use query API keys without justification.\n\nFix:\n\n* Move tokens to Authorization headers; rotate/shorten lifetimes; use POST bodies for sensitive values.\n\n---\n\n### FASTAPI-AUTH-003: Password storage MUST be strongly hashed; never store plaintext passwords\n\nSeverity: Critical\n\nRequired:\n\n* MUST store passwords using a strong, slow password hashing scheme (e.g., Argon2id, bcrypt).\n* MUST NOT store plaintext passwords, or reversible encryption as the primary protection.\n* SHOULD use established libraries for hashing and verification (do not roll your own).\n\nInsecure patterns:\n\n* Storing plaintext passwords in DB.\n* Using fast hashes (e.g., SHA256) without a proper password hashing KDF.\n* Returning password hashes in API responses.\n\nDetection hints:\n\n* Search for `password=` persisted fields, and look for `hashlib.md5/sha1/sha256` usage on passwords.\n* Inspect response models for password/hash fields.\n\nFix:\n\n* Migrate to a proper password hashing library; add a re-hash-on-login upgrade path.\n\n---\n\n### FASTAPI-AUTH-004: JWT validation MUST be strict; JWTs MUST NOT carry secrets\n\nSeverity: High\n\nRequired:\n\n* MUST validate JWT signature and enforce an algorithm allowlist.\n* MUST validate standard claims appropriate to your system (at least `exp`; typically also `iss`/`aud` if multi-service or multi-tenant).\n* MUST treat JWT contents as readable by the client; do not put secrets in JWT payloads. ([FastAPI][12])\n\nInsecure patterns:\n\n* `jwt.decode(..., options={\"verify_signature\": False})` or equivalent.\n* Accepting `alg=none` / algorithm confusion.\n* Using JWT payload to store sensitive secrets (API keys, passwords).\n\nDetection hints:\n\n* Search for `jwt.decode`, `python-jose`, `PyJWT`, `verify_signature`.\n* Check for missing exp validation or long expirations.\n\nFix:\n\n* Enforce strict validation (signature, allowed algorithms, exp, and any required issuer/audience constraints).\n* Store only identifiers/claims you are comfortable exposing to the client. ([FastAPI][12])\n\n---\n\n### FASTAPI-AUTHZ-001: Authorization MUST be enforced per-object and per-property\n\nSeverity: High\n\nRequired:\n\n* MUST perform object-level authorization whenever accessing a resource by user-controlled identifier (ID in path/query/body).\n* MUST perform property-level authorization and response shaping to prevent “excessive data exposure” (e.g., admin-only fields). ([OWASP Foundation][13])\n\nInsecure patterns:\n\n* `GET /users/{id}` returns user record without verifying caller can access that `id`.\n* Response models include internal fields (roles, permissions, billing data, password hashes).\n\nDetection hints:\n\n* Enumerate endpoints that accept IDs; trace whether an authz check is performed.\n* Compare response models for public vs internal fields.\n\nFix:\n\n* Add object-level checks (ownership, ACLs, tenant boundaries).\n* Use dedicated response models that include only allowed fields.\n\n---\n\n### FASTAPI-SESS-001: If using cookie-based sessions and TLS, cookie attributes MUST be secure in production\n\nSeverity: High (only if TLS is enabled)\n\nRequired (production, HTTPS):\n\n* MUST set session cookies to be sent only over HTTPS (secure). IMPORTANT NOTE: Only set `Secure` in production environment when TLS is configured. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n* MUST set HttpOnly for session cookies (not accessible to JS).\n* SHOULD use `SameSite=Lax` (or `Strict` if UX allows); if you require cross-site cookies, document the CSRF implications and add compensating controls. ([OWASP Cheat Sheet Series][8])\n* If using Starlette `SessionMiddleware`, MUST set `https_only=True` in production and choose an appropriate `same_site`. ([PyPI][5])\n\nInsecure patterns:\n\n* Session cookies without Secure/HttpOnly.\n* `SameSite=None` cookies used for authenticated state-changing endpoints without CSRF protections.\n\nDetection hints:\n\n* Search for `SessionMiddleware(` and inspect parameters like `https_only`, `same_site`.\n* Search for `set_cookie(` usage and cookie flags.\n\nFix:\n\n* Set secure cookie attributes; prefer short lifetimes for high-privilege sessions. ([OWASP Cheat Sheet Series][8])\n\n---\n\n### FASTAPI-SESS-002: Do not store sensitive secrets in signed session cookies\n\nSeverity: High\n\nRequired:\n\n* MUST assume cookie-based session data is readable by the client (signed ≠ encrypted); do not store secrets/PII unless encrypted server-side.\n* Store only opaque identifiers (e.g., session ID) or non-sensitive state in the cookie; store sensitive session state server-side. ([OWASP Cheat Sheet Series][8])\n\nInsecure patterns:\n\n* Storing access tokens, refresh tokens, or PII directly in cookie session payloads.\n* Treating “signed cookies” as confidential storage.\n\nDetection hints:\n\n* Search for `request.session[...] =` or `session[...] =`-equivalent patterns; identify what is stored.\n* Identify use of `SessionMiddleware` or other cookie session mechanisms.\n\nFix:\n\n* Move sensitive values to server-side storage; keep cookie minimal.\n\n---\n\n### FASTAPI-CSRF-001: Cookie-authenticated state-changing requests MUST be CSRF-protected\n\nSeverity: High\n\nNote: This only applies if using cookie based auth. If the application uses header or token based auth such as Authorization header, then CSRF is not an issue.\n\nRequired:\n\n* MUST protect all state-changing endpoints (POST/PUT/PATCH/DELETE) that rely on cookies for authentication.\n* SHOULD use a proven CSRF approach (synchronizer token pattern, or well-reviewed middleware) rather than rolling your own. ([OWASP Cheat Sheet Series][2])\n* MAY add defense-in-depth (Origin/Referer checks, SameSite cookies, Fetch Metadata), but tokens are the primary defense for cookie-authenticated apps. ([OWASP Cheat Sheet Series][2])\n* IMPORTANT NOTE: If cookies are not used for auth (auth is via `Authorization` header), CSRF is usually not applicable. ([FastAPI][11])\n\nInsecure patterns:\n\n* Cookie-authenticated endpoints that change state with no CSRF validation.\n* Using GET for state-changing actions (amplifies CSRF risk).\n\nDetection hints:\n\n* Enumerate routes with methods other than GET; identify whether cookies are used for auth.\n* Look for CSRF token generation/verification or middleware.\n\nFix:\n\n* Add CSRF tokens (and validate them) on state-changing actions when cookie auth is in use. ([OWASP Cheat Sheet Series][2])\n\n---\n\n### FASTAPI-VALID-001: Request parsing and validation MUST be schema-driven; prevent mass assignment\n\nSeverity: Medium (especially for APIs that write to DB)\n\nRequired:\n\n* SHOULD use Pydantic models for request bodies instead of accepting arbitrary `dict`/`Any`.\n* SHOULD configure models to reject unexpected fields where appropriate (prevents “mass assignment” style bugs).\n* MUST validate and normalize identifiers (IDs, email, URLs) before using them for access control or side effects. ([OWASP Cheat Sheet Series][14])\n\nInsecure patterns:\n\n* `payload = await request.json()` followed by `Model(**payload)` or direct DB writes with `payload` (no allowlist).\n* Models that silently accept unknown fields for write endpoints.\n\nDetection hints:\n\n* Search for `await request.json()`, `request.body()`, `dict`-typed bodies, `Any`-typed bodies.\n* Look for endpoints that do `db.update(**payload)` or `Model(**payload)` with unfiltered input.\n\nFix:\n\n* Use explicit Pydantic models with allowlisted fields; reject extras for write endpoints. ([OWASP Cheat Sheet Series][14])\n\n---\n\n### FASTAPI-RESP-001: Prevent excessive data exposure via response models and explicit serialization\n\nSeverity: Medium\n\nRequired:\n\n* MUST define response models that include only intended fields (especially for user objects, auth-related objects, billing objects).\n* SHOULD use separate models for “create input”, “db/internal”, and “public output” to avoid leaking sensitive fields. ([FastAPI][15])\n\nInsecure patterns:\n\n* Returning ORM objects or dicts that include internal columns.\n* Reusing “DB model” as the response model (includes `password_hash`, `is_admin`, etc).\n\nDetection hints:\n\n* Look for endpoints that `return user` where `user` is an ORM instance.\n* Check for `response_model` omissions on endpoints that return sensitive resources.\n\nFix:\n\n* Add explicit response models; create “public” schemas that exclude sensitive fields. ([FastAPI][15])\n\n---\n\n### FASTAPI-XSS-001: Prevent reflected/stored XSS in HTML responses and templates\n\nSeverity: High (if the service serves HTML)\n\nRequired:\n\n* MUST use templating with auto-escaping enabled for HTML.\n* MUST NOT mark untrusted content as safe (no unsafe “raw HTML” rendering of user-controlled data).\n* SHOULD deploy a CSP when serving HTML that includes any user content. ([OWASP Cheat Sheet Series][16])\n\nInsecure patterns:\n\n* Rendering user content directly into HTML without escaping/sanitization.\n* Disabling auto-escaping or using “raw HTML” features without sanitization.\n\nDetection hints:\n\n* Search for template rendering and string concatenation that builds HTML.\n* Review templates for “unsafe” filters/constructs and unquoted attributes.\n\nFix:\n\n* Keep auto-escaping on; sanitize user HTML only if absolutely required using a trusted sanitizer; add CSP. ([OWASP Cheat Sheet Series][16])\n\nNote:\n\n* If the app is a pure JSON API, XSS is usually a client/app concern, but error pages/docs pages might still render HTML.\n\n---\n\n### FASTAPI-SSTI-001: Never render untrusted templates (Server-Side Template Injection)\n\nSeverity: Critical\n\nRequired:\n\n* MUST NOT render templates that contain user-controlled template syntax.\n* MUST treat “template-from-string” rendering as dangerous if influenced by untrusted input.\n* If untrusted templates are absolutely required (rare, high-risk):\n\n  * MUST use a sandboxed templating approach and restrict capabilities.\n  * MUST assume sandbox escapes are possible; add isolation and strict allowlists. ([OWASP Foundation][17])\n\nInsecure patterns:\n\n* Rendering templates loaded from user input or DB via a normal Jinja environment.\n* Building templates dynamically using user-controlled strings.\n\nDetection hints:\n\n* Grep for Jinja `Environment.from_string`, `Template(...)`, or similar.\n* Trace origin of template string (request, DB, uploads, admin panels).\n\nFix:\n\n* Replace with non-executable templating (simple string substitution).\n* If truly needed, use Jinja’s sandbox environment plus strong isolation. ([jinja.palletsprojects.com][18])\n\n---\n\n### FASTAPI-HEADERS-001: Set essential security headers (in app or at the edge)\n\nSeverity: Medium\n\nRequired (typical API/web app):\n\n* SHOULD set:\n\n  * `X-Content-Type-Options: nosniff`\n  * Clickjacking protection (`X-Frame-Options` and/or CSP `frame-ancestors`) if HTML is served\n  * `Referrer-Policy` and `Permissions-Policy` as appropriate\n\nNOTE:\n\n* Headers may be set by a proxy/CDN. If not visible in app code, flag as “verify at edge”. ([OWASP Cheat Sheet Series][6])\n\nInsecure patterns:\n\n* No security headers anywhere (app or edge) for apps serving HTML or sensitive APIs.\n\nDetection hints:\n\n* Search for middleware that sets headers; check reverse proxy config.\n\nFix:\n\n* Set headers centrally (middleware) or via reverse proxy/CDN.\n\n---\n\n### FASTAPI-CORS-001: CORS MUST be explicit and least-privilege\n\nSeverity: Medium (High if misconfigured with credentials)\n\nRequired:\n\n* If CORS is not needed, MUST keep it disabled.\n* If CORS is needed:\n\n  * MUST allowlist trusted origins (do not reflect arbitrary origins).\n  * MUST NOT combine credentialed requests with wildcard origins (this is unsafe and commonly rejected by compliant middleware). ([OWASP Cheat Sheet Series][6])\n  * SHOULD restrict allowed methods and headers.\n\nInsecure patterns:\n\n* `allow_origins=[\"*\"]` together with `allow_credentials=True`.\n* Reflecting `Origin` without validation.\n* `allow_origin_regex=\".*\"` used broadly.\n\nDetection hints:\n\n* Search for `CORSMiddleware` configuration.\n* Look for `allow_origins=[\"*\"]`, `allow_credentials=True`, `allow_origin_regex`.\n\nFix:\n\n* Use an explicit origin allowlist and minimal methods/headers; keep credentials off unless required. ([OWASP Cheat Sheet Series][6])\n\n---\n\n### FASTAPI-HOST-001: Host header MUST be validated in production\n\nSeverity: Low\n\nRequired:\n\n* SHOULD use `TrustedHostMiddleware` (or equivalent at edge) to restrict accepted Host values. ([PyPI][5])\n* MUST NOT trust the `Host` header for security-sensitive decisions without validation.\n\nInsecure patterns:\n\n* No Host validation while generating external URLs (password reset links, callback URLs) from request host.\n* Allowing arbitrary Host headers in apps behind permissive proxies.\n\nDetection hints:\n\n* Search for `TrustedHostMiddleware` usage.\n* Search for logic that uses `request.url`, `request.base_url`, or host-derived values to build external URLs.\n\nFix:\n\n* Configure a strict allowed-hosts list in production; enforce at edge too if possible.\n\n---\n\n### FASTAPI-PROXY-001: Reverse proxy trust MUST be configured correctly\n\nSeverity: High (when behind a proxy)\n\nRequired:\n\n* If behind a reverse proxy, MUST configure forwarded-header trust correctly.\n* MUST NOT blindly trust `X-Forwarded-*` headers from the open internet.\n* If using Uvicorn proxy header support, MUST restrict which IPs are allowed to provide forwarded headers. ([PyPI][4])\n\nInsecure patterns:\n\n* Enabling proxy headers broadly without restricting trusted proxy IPs.\n* Using forwarded headers to decide “is secure” / “is internal” / “client IP” without proper trust boundaries.\n\nDetection hints:\n\n* Search for `--proxy-headers`, `--forwarded-allow-ips`, or equivalent config.\n* Search for security-sensitive use of `request.client.host`, `request.url.scheme`, `request.headers[\"x-forwarded-for\"]`.\n\nFix:\n\n* Configure Uvicorn with proxy headers only when behind a known proxy, and restrict `forwarded_allow_ips` to that proxy. ([PyPI][4])\n* Keep Host allowlisting in place even behind proxies.\n\n---\n\n### FASTAPI-LIMITS-001: Request and multipart limits MUST be enforced to prevent DoS\n\nSeverity: Low\n\nRequired:\n\n* MUST enforce request size limits at the edge (reverse proxy/load balancer) and validate in app where needed.\n* MUST apply special scrutiny to multipart/form-data handling; historical vulnerabilities include unbounded buffering and DoS vectors. ([advisories.gitlab.com][9])\n* SHOULD rate limit and/or add per-IP/per-user throttles for expensive endpoints.\n\nInsecure patterns:\n\n* Accepting arbitrarily large JSON bodies or multipart forms.\n* Parsing multipart forms without size/field-count controls.\n\nDetection hints:\n\n* Identify file upload endpoints and `multipart/form-data` usage.\n* Look for missing proxy-level limits (nginx `client_max_body_size`, ALB limits, etc.) and missing app-level checks.\n\nFix:\n\n* Enforce strict body limits and multipart constraints; keep Starlette and python-multipart updated to patched versions. ([advisories.gitlab.com][9])\n\n---\n\n### FASTAPI-FILES-001: Prevent path traversal and unsafe static file exposure\n\nSeverity: High\n\nRequired:\n\n* MUST NOT pass user-controlled file paths to `FileResponse`/filesystem calls without strict validation and safe base directories.\n* If using `StaticFiles`, MUST keep Starlette updated and understand the security history (path traversal advisory exists for older versions). ([advisories.gitlab.com][10])\n* MUST NOT serve user uploads as executable/active content (especially HTML/JS) from a static root without safe handling.\n\nInsecure patterns:\n\n* `FileResponse(request.query_params[\"path\"])`\n* Mounting `StaticFiles(directory=\"uploads\")` where uploads include HTML/JS/SVG and are served inline.\n\nDetection hints:\n\n* Search for `FileResponse(`, `StaticFiles(`, `open(` in routes.\n* Trace whether the path originates from untrusted input.\n\nFix:\n\n* Use opaque IDs for files; map IDs to server-side stored paths.\n* Serve untrusted content as attachment downloads where appropriate.\n\n---\n\n### FASTAPI-FILES-002: Mitigate Range-header DoS on file-serving endpoints\n\nSeverity: Low (if affected versions and file serving is enabled)\n\nRequired:\n\n* MUST keep Starlette patched against known file-serving DoS issues if using `FileResponse`/`StaticFiles`.\n* MUST treat unusual `Range` header handling and file serving as a DoS surface. ([advisories.gitlab.com][19])\n\nInsecure patterns:\n\n* Serving large files with vulnerable Starlette versions.\n* No rate limiting / CDN shielding for file endpoints.\n\nDetection hints:\n\n* Identify Starlette version; if in affected range, flag.\n* Find uses of `FileResponse` and `StaticFiles`.\n\nFix:\n\n* Upgrade Starlette to a fixed version per advisory guidance. ([advisories.gitlab.com][19])\n* Add edge caching/rate limiting for file endpoints where appropriate.\n\n---\n\n### FASTAPI-UPLOAD-001: File uploads MUST be validated, stored safely, and served safely\n\nSeverity: Medium\n\nRequired:\n\n* MUST enforce upload size limits (app + edge).\n* MUST validate file type using allowlists and content checks (not only extension). ([OWASP Cheat Sheet Series][20])\n* SHOULD generate server-side filenames (random IDs) and avoid trusting original names.\n* MUST serve potentially active formats safely (download attachment) unless explicitly intended.\n\nInsecure patterns:\n\n* Accepting arbitrary file types and serving them back inline.\n* Using user-supplied filename as storage path.\n\nDetection hints:\n\n* Look for upload handlers and where/how files are written.\n* Look for direct exposure of upload directories.\n\nFix:\n\n* Implement allowlist validation + safe storage + safe serving; add scanning/quarantine if applicable. ([OWASP Cheat Sheet Series][20])\n\n---\n\n### FASTAPI-INJECT-001: Prevent SQL injection (use parameterized queries / ORM)\n\nSeverity: High\n\nRequired:\n\n* MUST use parameterized queries or an ORM that parameterizes under the hood.\n* MUST NOT build SQL by string concatenation / f-strings with untrusted input. ([OWASP Cheat Sheet Series][21])\n\nInsecure patterns:\n\n* `f\"SELECT ... WHERE id={user_id}\"`\n* `\"... WHERE name = '%s'\" % user_input`\n\nDetection hints:\n\n* Grep for SQL keywords in Python strings near `.execute(...)`.\n* Trace untrusted data into DB calls.\n\nFix:\n\n* Replace with parameterized queries / ORM query APIs; validate types before querying. ([OWASP Cheat Sheet Series][21])\n\n---\n\n### FASTAPI-INJECT-002: Prevent OS command injection\n\nSeverity: Critical to High (depends on exposure)\n\nRequired:\n\n* MUST avoid executing shell commands with untrusted input.\n* If subprocess is necessary:\n\n  * MUST pass args as a list (not a string)\n  * MUST NOT use `shell=True` with attacker-influenced strings\n  * SHOULD use strict allowlists for any variable component ([OWASP Cheat Sheet Series][22])\n\nInsecure patterns:\n\n* `os.system(user_input)`\n* `subprocess.run(f\"cmd {user}\", shell=True)`\n* Passing user strings into `bash -c`, `sh -c`, PowerShell, etc.\n\nDetection hints:\n\n* Search for `os.system`, `subprocess`, `Popen`, `shell=True`.\n* Trace data from request/DB into these calls.\n\nFix:\n\n* Use library APIs instead of shell commands.\n* If unavoidable, hard-code the command and allowlist validated parameters; use `--` separator where supported. ([OWASP Cheat Sheet Series][22])\n\n---\n\n### FASTAPI-SSRF-001: Prevent server-side request forgery (SSRF) in outbound HTTP\n\nSeverity: Medium (can be High in cloud/VPC environments)\n\n- Note: For small stand alone projects this is less important. It is most important when deploying into an LAN or with other services listening on the same server.\n\nRequired:\n\n* MUST treat outbound requests to user-provided URLs as high risk.\n* SHOULD validate and restrict destinations (allowlist hosts/domains) for any user-influenced URL fetch.\n* SHOULD block access to localhost/private IP ranges/link-local and cloud metadata endpoints.\n* MUST restrict protocols to http/https.\n* SHOULD set timeouts and carefully control redirects. ([OWASP Cheat Sheet Series][23])\n\nInsecure patterns:\n\n* `httpx.get(request.query_params[\"url\"])`\n* “URL preview/import/webhook tester” features that accept arbitrary URLs.\n\nDetection hints:\n\n* Search for `requests`, `httpx`, `urllib`, `aiohttp` calls with URLs derived from requests/DB.\n* Identify endpoints named `fetch`, `preview`, `proxy`, `webhook`, `import`.\n\nFix:\n\n* Implement strict URL parsing + allowlists; add egress controls; set short timeouts; disable redirects if not required. ([OWASP Cheat Sheet Series][23])\n\n---\n\n### FASTAPI-REDIRECT-001: Prevent open redirects\n\nSeverity: Low\n\nRequired:\n\n* MUST validate redirect targets derived from untrusted input (`next`, `redirect`, `return_to`).\n* SHOULD prefer redirecting only to same-site relative paths or an allowlist of domains. ([OWASP Cheat Sheet Series][24])\n\nInsecure patterns:\n\n* Returning `RedirectResponse(next)` where `next` is user-controlled with no validation.\n\nDetection hints:\n\n* Search for `RedirectResponse(` or redirect logic and examine the source of the target.\n\nFix:\n\n* Allow only relative paths or allowlisted domains; fall back to a safe default. ([OWASP Cheat Sheet Series][24])\n\n---\n\n### FASTAPI-WS-001: WebSocket endpoints MUST be authenticated and protected against cross-site abuse\n\nSeverity: Medium to High (depends on data/privilege)\n\nRequired:\n\n* MUST authenticate WebSocket connections for any non-public channel (WebSockets don’t inherently provide auth). ([OWASP Cheat Sheet Series][25])\n* SHOULD enforce origin/CSRF-like protections appropriate for browser-based WebSocket clients (Origin validation is a common control).\n* SHOULD rate limit message frequency and connection attempts; close idle/abusive connections.\n\nInsecure patterns:\n\n* `@app.websocket(...)` accepts and trusts the connection with no auth check.\n* Using query-string tokens for auth without considering leakage/rotation.\n\nDetection hints:\n\n* Search for `@app.websocket` / `websocket_endpoint` and inspect whether auth is performed before accepting sensitive operations.\n* Review origin checks, token parsing, and per-connection authorization.\n\nFix:\n\n* Require authentication during handshake (e.g., a token or session) and enforce authorization for actions/messages.\n* Validate Origin for browser-based clients where appropriate; apply rate limits and timeouts. ([OWASP Cheat Sheet Series][25])\n\n---\n\n### FASTAPI-SUPPLY-001: Dependency and patch hygiene (focus on security-relevant deps)\n\nSeverity: Low\n\nRequired:\n\n* SHOULD pin and regularly update security-critical dependencies (FastAPI, Starlette, Uvicorn, Pydantic, python-multipart, auth/JWT libs).\n* MUST respond to known security advisories promptly.\n* MUST treat file serving and multipart parsing dependencies as security-sensitive due to historical CVEs. ([advisories.gitlab.com][10])\n\nAudit focus examples (historical):\n\n* Starlette StaticFiles path traversal (fixed in 0.27.0). ([advisories.gitlab.com][10])\n* Starlette multipart/form-data DoS (fixed in 0.40.0). ([advisories.gitlab.com][9])\n* Starlette FileResponse Range header DoS (fixed in 0.49.1). ([advisories.gitlab.com][19])\n\nDetection hints:\n\n* Check `requirements.txt`, lockfiles, container images, and runtime environments for actual installed versions.\n* Map file upload/file serving features to dependency versions.\n\nFix:\n\n* Upgrade to patched versions per advisories; add regression tests around affected behavior.\n\n---\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n* Dev server / debug:\n\n  * `--reload`, `reload=True`, `debug=True`, `FastAPI(debug=True)` ([PyPI][4])\n* OpenAPI/docs exposure:\n\n  * `/docs`, `/redoc`, `/openapi.json`, `docs_url=`, `openapi_url=`\n* Auth enforcement gaps:\n\n  * Endpoints missing `Depends()`/`Security()` where expected; routers without a consistent dependency boundary ([FastAPI][7])\n  * Tokens in query params (`token=`, `api_key=`, `key=`) ([FastAPI][11])\n* Session/cookies + CSRF:\n\n  * `SessionMiddleware(` and cookie flags (`https_only`, `same_site`) ([PyPI][5])\n  * POST/PUT/PATCH/DELETE handlers using cookie auth with no CSRF checks ([OWASP Cheat Sheet Series][2])\n* Input validation & mass assignment:\n\n  * `await request.json()` and direct DB writes from dicts; models accepting extra fields ([OWASP Cheat Sheet Series][14])\n* Excessive data exposure:\n\n  * Returning ORM objects or dicts without `response_model`; responses containing password/role/internal fields ([FastAPI][15])\n* CORS:\n\n  * `CORSMiddleware` with `allow_origins=[\"*\"]`, `allow_origin_regex=\".*\"`, `allow_credentials=True` ([OWASP Cheat Sheet Series][6])\n* Files:\n\n  * `FileResponse(` with user-controlled paths; `StaticFiles(` exposing uploads ([advisories.gitlab.com][10])\n* Uploads / multipart:\n\n  * `multipart/form-data` endpoints with no size/field constraints; outdated Starlette/python-multipart ([advisories.gitlab.com][9])\n* Injection:\n\n  * SQL strings with f-strings/concatenation into `.execute(...)` ([OWASP Cheat Sheet Series][21])\n  * `subprocess.*`, `shell=True`, `os.system` ([OWASP Cheat Sheet Series][22])\n* SSRF:\n\n  * `httpx.get/post` or `requests.*` with URL from request/DB, no allowlist/timeouts ([OWASP Cheat Sheet Series][23])\n* Redirect:\n\n  * `RedirectResponse(next)` with no validation ([OWASP Cheat Sheet Series][24])\n* WebSockets:\n\n  * `@app.websocket` handlers without auth/origin checks; use of `ws://` in prod configs ([FastAPI][27])\n\nAlways try to confirm:\n\n* data origin (untrusted vs trusted)\n* sink type (SQL/subprocess/files/template/http/redirect/ws)\n* protective controls present (validation, allowlists, middleware, edge controls)\n* installed dependency versions vs vulnerable ranges ([advisories.gitlab.com][10])\n\n---\n\n## 6) Sources (accessed 2026-01-27)\n\nPrimary framework documentation:\n\n* FastAPI (PyPI metadata, versioning) — `https://pypi.org/project/fastapi/` ([PyPI][1])\n* FastAPI docs: Security “First Steps” (Authorization Bearer header conventions) — `https://fastapi.tiangolo.com/tutorial/security/first-steps/` ([FastAPI][11])\n* FastAPI reference: Dependencies (`Depends`, `Security`) — `https://fastapi.tiangolo.com/reference/dependencies/` ([FastAPI][7])\n* FastAPI reference: APIRouter (router-level dependencies) — `https://fastapi.tiangolo.com/reference/apirouter/` ([FastAPI][28])\n* FastAPI docs: WebSockets — `https://fastapi.tiangolo.com/advanced/websockets/` ([FastAPI][27])\n\nASGI/server stack documentation:\n\n* Starlette (PyPI, general capabilities) — `https://pypi.org/project/starlette/` ([PyPI][5])\n* Starlette docs: WebSockets — `https://starlette.dev/websockets/` ([Starlette][3])\n* Uvicorn (PyPI metadata) — `https://pypi.org/project/uvicorn/` ([PyPI][4])\n* Pydantic docs (v2.12.x) — `https://docs.pydantic.dev/latest/` ([Pydantic][29])\n\nSecurity standards and cheat sheets:\n\n* OWASP Cheat Sheet Series: Session Management — `https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][8])\n* OWASP Cheat Sheet Series: CSRF Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][2])\n* OWASP Cheat Sheet Series: XSS Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][16])\n* OWASP Cheat Sheet Series: Mass Assignment — `https://cheatsheetseries.owasp.org/cheatsheets/Mass_Assignment_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][14])\n* OWASP API Security Top 10 (2023) — `https://owasp.org/API-Security/editions/2023/en/0x11-t10/` ([OWASP Foundation][13])\n* OWASP Cheat Sheet Series: SQL Injection Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][21])\n* OWASP Cheat Sheet Series: OS Command Injection Defense — `https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][22])\n* OWASP Cheat Sheet Series: SSRF Prevention — `https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][23])\n* OWASP Cheat Sheet Series: File Upload — `https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][20])\n* OWASP Cheat Sheet Series: Unvalidated Redirects and Forwards — `https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][24])\n* OWASP Cheat Sheet Series: HTTP Security Response Headers — `https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][6])\n* OWASP Cheat Sheet Series: WebSocket Security — `https://cheatsheetseries.owasp.org/cheatsheets/WebSocket_Security_Cheat_Sheet.html` ([OWASP Cheat Sheet Series][25])\n* OWASP WSTG: Testing for Server-Side Template Injection — `https://owasp.org/www-project-web-security-testing-guide/v41/4-Web_Application_Security_Testing/07-Input_Validation_Testing/18-Testing_for_Server_Side_Template_Injection` ([OWASP Foundation][17])\n* OWASP WSTG: Testing WebSockets — `https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/11-Client-side_Testing/10-Testing_WebSockets` ([OWASP Foundation][26])\n\nTemplate safety references:\n\n* Jinja: Sandbox — `https://jinja.palletsprojects.com/en/stable/sandbox/` ([jinja.palletsprojects.com][18])\n\nSelected supply-chain/advisory references (Starlette examples):\n\n* CVE-2023-29159 (StaticFiles path traversal; fixed 0.27.0) — `https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2023-29159/` ([advisories.gitlab.com][10])\n* CVE-2024-47874 (multipart/form-data DoS; fixed 0.40.0) — `https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2024-47874/` ([advisories.gitlab.com][9])\n* CVE-2025-62727 (FileResponse Range header DoS; fixed 0.49.1) — `https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2025-62727/` ([advisories.gitlab.com][19])\n\n[1]: https://pypi.org/project/fastapi/ \"https://pypi.org/project/fastapi/\"\n[2]: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html\"\n[3]: https://starlette.dev/websockets/?utm_source=chatgpt.com \"Websockets\"\n[4]: https://pypi.org/project/uvicorn/ \"https://pypi.org/project/uvicorn/\"\n[5]: https://pypi.org/project/starlette/ \"https://pypi.org/project/starlette/\"\n[6]: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html?utm_source=chatgpt.com \"HTTP Security Response Headers Cheat Sheet\"\n[7]: https://fastapi.tiangolo.com/reference/dependencies/?utm_source=chatgpt.com \"Dependencies - Depends() and Security() - FastAPI\"\n[8]: https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html\"\n[9]: https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2024-47874/ \"Starlette Denial of service (DoS) via multipart/form-data | GitLab Advisory Database\"\n[10]: https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2023-29159/ \"Starlette has Path Traversal vulnerability in StaticFiles | GitLab Advisory Database\"\n[11]: https://fastapi.tiangolo.com/tutorial/security/first-steps/?utm_source=chatgpt.com \"Security - First Steps - FastAPI\"\n[12]: https://fastapi.tiangolo.com/tutorial/response-model/ \"https://fastapi.tiangolo.com/tutorial/response-model/\"\n[13]: https://owasp.org/API-Security/editions/2023/en/0x11-t10/ \"https://owasp.org/API-Security/editions/2023/en/0x11-t10/\"\n[14]: https://cheatsheetseries.owasp.org/cheatsheets/Mass_Assignment_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Mass_Assignment_Cheat_Sheet.html\"\n[15]: https://fastapi.tiangolo.com/tutorial/extra-models/ \"https://fastapi.tiangolo.com/tutorial/extra-models/\"\n[16]: https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html\"\n[17]: https://owasp.org/www-project-web-security-testing-guide/v41/4-Web_Application_Security_Testing/07-Input_Validation_Testing/18-Testing_for_Server_Side_Template_Injection?utm_source=chatgpt.com \"Testing for Server Side Template Injection\"\n[18]: https://jinja.palletsprojects.com/en/stable/sandbox/?utm_source=chatgpt.com \"Sandbox — Jinja Documentation (3.1.x)\"\n[19]: https://advisories.gitlab.com/pkg/pypi/starlette/CVE-2025-62727/ \"Starlette vulnerable to O(n^2) DoS via Range header merging in ``starlette.responses.FileResponse`` | GitLab Advisory Database\"\n[20]: https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html\"\n[21]: https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html\"\n[22]: https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html\"\n[23]: https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html \"https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html\"\n[24]: https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html?utm_source=chatgpt.com \"Unvalidated Redirects and Forwards Cheat Sheet\"\n[25]: https://cheatsheetseries.owasp.org/cheatsheets/WebSocket_Security_Cheat_Sheet.html?utm_source=chatgpt.com \"WebSocket Security - OWASP Cheat Sheet Series\"\n[26]: https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/11-Client-side_Testing/10-Testing_WebSockets?utm_source=chatgpt.com \"WSTG - Latest | OWASP Foundation\"\n[27]: https://fastapi.tiangolo.com/advanced/websockets/?utm_source=chatgpt.com \"WebSockets - FastAPI\"\n[28]: https://fastapi.tiangolo.com/reference/apirouter/?utm_source=chatgpt.com \"APIRouter class - FastAPI\"\n[29]: https://docs.pydantic.dev/latest/ \"https://docs.pydantic.dev/latest/\"\n\n<!-- File: core/skills/builtin/security-best-practices/references/python-flask-web-server-security.md (Tokens: ~7077 | Category: anthropic-skill) -->\n# Flask (Python) Web Security Spec (Flask 3.1.x, Python 3.x)\n\nThis document is designed as a **security spec** that supports:\n1) **Secure-by-default code generation** for new Flask code.\n2) **Security review / vulnerability hunting** in existing Flask code (passive “notice issues while working” and active “scan the repo and report findings”).\n\nIt is intentionally written as a set of **normative requirements** (“MUST/SHOULD/MAY”) plus **audit rules** (what bad patterns look like, how to detect them, and how to fix/mitigate them).\n\n--------------------------------------------------------------------\n\n## 0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)\n\n- MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session cookies, SECRET_KEY).\n- MUST NOT “fix” security by disabling protections (e.g., turning off CSRF, relaxing CORS, disabling escaping, disabling auth checks).\n- MUST provide **evidence-based findings** during audits: cite file paths, code snippets, and configuration values that justify the claim.\n- MUST treat uncertainty honestly: if a protection might exist in infrastructure (reverse proxy, WAF, CDN), report it as “not visible in app code; verify at runtime/config”.\n\n--------------------------------------------------------------------\n\n## 1) Operating modes\n\n### 1.1 Generation mode (default)\nWhen asked to write new Flask code or modify existing code:\n- MUST follow every **MUST** requirement in this spec.\n- SHOULD follow every **SHOULD** requirement unless the user explicitly says otherwise.\n- MUST prefer safe-by-default APIs and proven libraries over custom security code.\n- MUST avoid introducing new risky sinks (template rendering from strings, shell execution, dynamic imports, unsafe redirects, serving user files as HTML, etc.).\n\n### 1.2 Passive review mode (always on while editing)\nWhile working anywhere in a Flask repo (even if the user did not ask for a security scan):\n- MUST “notice” violations of this spec in touched/nearby code.\n- SHOULD mention issues as they come up, with a brief explanation + safe fix.\n\n### 1.3 Active audit mode (explicit scan request)\nWhen the user asks to “scan”, “audit”, or “hunt for vulns”:\n- MUST systematically search the codebase for violations of this spec.\n- MUST output findings in a structured format (see §2.3).\n\nRecommended audit order:\n1) App entrypoints / deployment scripts / Dockerfiles / Procfiles.\n2) Flask configuration and environment handling.\n3) Auth + sessions + cookies.\n4) CSRF protections and state-changing routes.\n5) Template rendering and XSS/SSTI.\n6) File handling (uploads + downloads) and path traversal.\n7) Injection classes (SQL, command execution, unsafe deserialization).\n8) Outbound requests (SSRF).\n9) Redirect handling (open redirects).\n10) CORS and security headers.\n\n--------------------------------------------------------------------\n\n## 2) Definitions and review guidance\n\n### 2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)\nExamples include:\n- `request.args`, `request.form`, `request.values`\n- `request.get_json()`, `request.json`, `request.data`\n- `request.headers`, `request.cookies`\n- URL path parameters (e.g., `/user/<id>`)\n- Any data from external systems (webhooks, third-party APIs, message queues)\n- Any persisted user content (DB rows) that originated from users\n\n### 2.2 State-changing request\nA request is state-changing if it can create/update/delete data, change auth/session state, trigger side effects (purchase, email send, webhook send), or initiate privileged actions.\n\n### 2.3 Required audit finding format\nFor each issue found, output:\n\n- Rule ID:\n- Severity: Critical / High / Medium / Low\n- Location: file path + function/route name + line(s)\n- Evidence: the exact code/config snippet\n- Impact: what could go wrong, who can exploit it\n- Fix: safe change (prefer minimal diff)\n- Mitigation: defense-in-depth if immediate fix is hard\n- False positive notes: what to verify if uncertain\n\n--------------------------------------------------------------------\n\n## 3) Secure baseline: minimum production configuration (MUST in production)\n\nThis is the smallest “production baseline” that prevents common Flask misconfigurations.\n\n### 3.1 App initialization pattern (SHOULD)\nSHOULD use an app factory and environment-based config so production config is not hard-coded.\n\nExample skeleton (illustrative; adjust to your project):\n- Load config from environment / secret store.\n- Fail closed if critical settings are missing in production.\n\nKey baseline config targets:\n- `SECRET_KEY` set and not committed\n- `SESSION_COOKIE_SECURE=True` (when HTTPS) IMPORTANT NOTE: Only set `Secure` in production environment when TLS is configured. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n- `SESSION_COOKIE_HTTPONLY=True`\n- `SESSION_COOKIE_SAMESITE='Lax'` (or `'Strict'` if compatible)\n- `TRUSTED_HOSTS` set in production\n- Security headers set (CSP, etc.) either in app or at the edge\n\n--------------------------------------------------------------------\n\n## 4) Rules (generation + audit)\n\nEach rule contains: required practice, insecure patterns, detection hints, and remediation.\n\n### FLASK-DEPLOY-001: Do not use Flask’s development server in production\nSeverity: High (if production)\n\nRequired:\n- MUST NOT deploy the built-in development server as the production server.\n- MUST run behind a production-grade WSGI server or managed platform (such as gunicorn)\n\nInsecure patterns:\n- `app.run(...)` in a production entrypoint.\n- Deployment docs/scripts that use `flask run` in production.\n\nDetection hints:\n- Search for `app.run(`, `flask run`, `--debug`, `FLASK_DEBUG`, `FLASK_ENV=development`.\n- Check Docker CMD/ENTRYPOINT, Procfile, systemd units, shell scripts.\n\nFix:\n- Use a production WSGI server (and keep Flask as the app object).\n- Ensure the dev server is only used for local development.\n\nNote:\n- These are often used in dev mode or local testing. This is allowed. Only flag if it is clear that it is being used as the production entrypoint\n\n---\n\n### FLASK-DEPLOY-002: Debug mode MUST be disabled in production\nSeverity: Critical\n\nRequired:\n- MUST NOT enable debug mode in production.\n- MUST treat the interactive debugger as equivalent to remote code execution if exposed.\n\nInsecure patterns:\n- `app.run(debug=True)`\n- `flask run --debug` in production.\n- `DEBUG=True` via env/config in production.\n\nDetection hints:\n- Look for `debug=True`, `FLASK_DEBUG=1`, `DEBUG = True`, `app.debug = True`.\n- Look for `TRAP_HTTP_EXCEPTIONS`/debugger settings enabled in non-test contexts.\n\nFix:\n- Ensure debug is only enabled in local dev/test.\n- Prefer environment-based toggles and safe defaults.\n\nNote:\n- These are often used in dev mode or local testing. This is allowed. Only flag if it is clear that it is being used as the production entrypoint\n\n---\n\n### FLASK-CONFIG-001: SECRET_KEY must be strong, secret, and rotated safely\nSeverity: High (Critical if missing in production with sessions or signing)\n\nRequired:\n- MUST set a strong random `SECRET_KEY` in production.\n- MUST keep `SECRET_KEY` out of source control and out of logs.\n- MAY rotate keys periodically; MAY use `SECRET_KEY_FALLBACKS` to support rotation without instantly invalidating existing sessions, then remove old keys after the rotation window. This likely is not needed for smaller applications but is good practice for larger applications. As this may complicate deployment, suggest that it be implemented rather than implementing it by default.\n\nInsecure patterns:\n- Missing `SECRET_KEY` in production.\n- Hard-coded `SECRET_KEY` in repo (including test keys accidentally used in prod).\n- Logging or printing `SECRET_KEY`.\n\nDetection hints:\n- Search for `SECRET_KEY =`, `app.secret_key =`, `SECRET_KEY_FALLBACKS =`.\n- Check `.env` files committed to repo.\n- Check config modules for constants.\n\nFix:\n- Load from secret manager or environment variable.\n- Add a rotation process:\n  - Set new `SECRET_KEY`\n  - Keep old key(s) temporarily in `SECRET_KEY_FALLBACKS`\n  - Remove old key(s) after the safe window.\n\nNotes:\n- If the application uses Flask sessions (cookie-based by default), `SECRET_KEY` is directly security-critical.\n\n---\n\n### FLASK-SESS-001: Session cookies must use secure attributes in production\nSeverity: Medium\n\nRequired (production, HTTPS):\n- MUST set `SESSION_COOKIE_SECURE=True` (cookies only over HTTPS). NOTE: Only set `Secure` in production environment when TLS is configured. When running in a local dev environment over HTTP, do not set `Secure` property on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property like `SESSION_COOKIE_SECURE` which can be used to disable `Secure` cookies when testing over HTTP.\n- MUST ensure `SESSION_COOKIE_HTTPONLY=True` (protect from JS access).\n- SHOULD set `SESSION_COOKIE_SAMESITE='Lax'` (recommended) or `'Strict'` if compatible with UX.\n- SHOULD keep `SESSION_COOKIE_DOMAIN=None` unless you explicitly need subdomain-wide cookies.\n- If you need embedded/iframe third-party usage, MAY consider `SESSION_COOKIE_PARTITIONED=True` (requires HTTPS).\n\nInsecure patterns:\n- `SESSION_COOKIE_SECURE=False` in production.\n- `SESSION_COOKIE_HTTPONLY=False`.\n- `SESSION_COOKIE_SAMESITE=None` with cookie-authenticated state-changing endpoints (higher CSRF risk).\n\nDetection hints:\n- Inspect `app.config.update(...)` blocks and config classes.\n- Look for `set_cookie(..., secure=..., httponly=..., samesite=...)` usage on non-session cookies too.\n\nFix:\n- Set these config values explicitly in production config.\n\nNotes:\n- SameSite is defense-in-depth; do not treat it as a full replacement for CSRF tokens.\n\n---\n\n### FLASK-SESS-002: Sessions must be bounded and resistant to fixation/replay\nSeverity: Medium\n\nRequired:\n- SHOULD set a bounded session lifetime appropriate to the app.\n- SHOULD set `session.permanent = True` only when you intend persistent sessions, and set `PERMANENT_SESSION_LIFETIME` to a justified value.\n- SHOULD clear the session on login and privilege changes to reduce session fixation risk.\n- MUST NOT store sensitive secrets in the default Flask session cookie. The default session is signed, not encrypted.\n\nInsecure patterns:\n- Extremely long or unlimited lifetimes for privileged sessions.\n- No session clearing on login.\n- Storing secrets (passwords, access tokens, PII) directly in `session[...]` when using default cookie sessions.\n\nDetection hints:\n- Search for `PERMANENT_SESSION_LIFETIME`, `session.permanent`, `session[...] =`.\n- Identify whether server-side session storage is used; if not, assume default cookie sessions.\n\nFix:\n- Set appropriate lifetimes.\n- Clear/rotate session on login.\n- Store sensitive data server-side; store only identifiers in the session cookie.\n\n---\n\n### FLASK-CSRF-001: State-changing requests using cookie auth MUST be CSRF-protected\nSeverity: High\n\n- IMPORTANT NOTE: If cookies are not being used for auth (ie auth is via Authentication header or other passed token), then there is no CSRF risk.\n\nRequired:\n- MUST protect all state-changing endpoints (POST/PUT/PATCH/DELETE) that rely on cookies for authentication.\n- MAY use a well-tested CSRF library/integration (form framework or middleware) rather than rolling your own.\n- MAY use additional defenses (Origin/Referer checking, SameSite cookies, Fetch Metadata headers, custom headers for AJAX/API), but tokens remain the primary defense for cookie-authenticated apps.\nIf tokens are impractical, or for small applications:\n* MUST at a minimum require a custom header to be set and set the session cookie SESSION_COOKIE_SAMESITE=lax, as this is the strongest method besides requiring a form token, and may be much easier to implement.\n\nInsecure patterns:\n- Cookie-authenticated endpoints that change state with no CSRF protection.\n- Using GET for state-changing actions (amplifies CSRF risk).\n\nDetection hints:\n- Enumerate routes with methods other than GET and identify auth mechanism.\n- Look for CSRF integrations (e.g., Flask-WTF, global CSRF middleware). If absent, treat as suspicious.\n- Check JSON API endpoints too, not only HTML forms.\n\nFix:\n- Add CSRF protection to all state-changing requests.\n- If the app is a pure API and uses Authorization headers (bearer tokens) rather than cookies, document that choice and ensure cookies aren’t used for auth. If cookies are not used for auth, there is no CSRF risk.\n\nNotes:\n- XSS can defeat CSRF protections; CSRF defenses do not replace XSS prevention.\n\n---\n\n### FLASK-XSS-001: Prevent reflected/stored XSS in templates and HTML generation\nSeverity: High\n\nRequired:\n- MUST rely on Jinja auto-escaping for HTML templates.\n- MUST NOT mark untrusted content as safe:\n  - Avoid `Markup(...)` on user data.\n  - Avoid Jinja `|safe` on user-controlled content.\n- MUST quote HTML attributes containing Jinja expressions (`value=\"{{ x }}\"` not `value={{ x }}`).\n- MUST NOT serve uploaded HTML as active HTML; serve as download (`Content-Disposition: attachment`) or transform to a safe format. Note: This is only relevant if it is possible to upload document content such as html, js, css, etc. If it purely is image files, there is no concern.\n- SHOULD deploy a Content Security Policy (CSP) to mitigate XSS classes (including `javascript:` in `href`).\n\nInsecure patterns:\n- `Markup(request.args.get(...))`\n- Template filters: `{{ user_html|safe }}`\n- Unquoted attributes in templates\n- Serving user-uploaded content directly with `text/html` or inline rendering\n\nDetection hints:\n- Search for `Markup(` and investigate origin of the data.\n- Search template files for `|safe`, `|tojson` misuse, and unquoted attributes.\n- Review file-serving routes that might return user uploads without `as_attachment=True`. Note: This is only relevant if it is possible to upload document content such as html, js, css, etc. If it purely is image files, there is no concern.\n\nFix:\n- Remove unsafe marking; sanitize only when strictly necessary using a trusted HTML sanitizer.\n- Always quote attributes.\n- Add CSP and reduce inline scripts.\n\n---\n\n### FLASK-SSTI-001: Never render untrusted templates (Server-Side Template Injection)\nSeverity: Critical\n\nRequired:\n- MUST NOT render templates that contain user-controlled template syntax.\n- MUST treat `render_template_string` and `Environment.from_string(...).render(...)` as dangerous if the template string is influenced by untrusted input.\n- MUST NOT use use `.format()` on user controlled strings\n- If untrusted templates are absolutely required, treat it as a special high-risk design:\n  - MUST use a sandboxed templating approach and restrict capabilities.\n  - MUST keep Jinja updated and assume sandbox escapes are possible; isolate further.\n\nInsecure patterns:\n- `render_template_string(request.args[\"tmpl\"], ...)`\n- Storing user templates in DB and rendering them with the normal Jinja environment.\n- `request.args[\"tmpl\"].format(...)`\n\nDetection hints:\n- Grep for `render_template_string`, `from_string`, `.render(` with dynamic strings.\n- Trace the origin of the template string (DB, request, uploads, admin panels).\n\nFix:\n- Replace with safe templating alternatives that do not evaluate code (e.g., string.Template, str.replace).\n- If templates must be user-defined, use a sandbox plus strict allowlists and heavy isolation.\n\n---\n\n### FLASK-HEADERS-001: Set essential security headers (in app or at the edge)\nSeverity: Medium\n\nRequired (typical web app):\n- SHOULD set:\n  - CSP (`Content-Security-Policy`)\n  - `X-Content-Type-Options: nosniff`\n  - Clickjacking protection (`X-Frame-Options: SAMEORIGIN` and/or CSP `frame-ancestors`) (there may be cases where the user wants to iframe their site elsewhere. If that is the case, work with them to safely allow it)\n- SHOULD consider additional hardening headers depending on app (Referrer-Policy, Permissions-Policy).\n- MUST ensure cookies are set with secure attributes (see FLASK-SESS-001).\n\nNOTE: Security headers may be set via a proxy or other cloud provider. Check to see if there is evidence of that.\n\nInsecure patterns:\n- No security headers anywhere (app or edge).\n- CSP missing on apps that display untrusted content.\n\nDetection hints:\n- Search for `after_request` hooks, Flask-Talisman usage, reverse proxy config.\n- If not visible in app code, flag as “verify at edge”.\n\nFix:\n- Set headers centrally (middleware / after_request) or via reverse proxy/CDN.\n- Keep CSP realistic and compatible; avoid `unsafe-inline` where possible.\n\n---\n\n### FLASK-LIMITS-001: Request size and form parsing limits MUST be set appropriately\nSeverity: Low (Medium if file uploads / large bodies are possible)\n\nRequired:\n- SHOULD set and justify:\n  - `MAX_CONTENT_LENGTH` (global maximum request bytes)\n  - `MAX_FORM_MEMORY_SIZE` (max per non-file form field in multipart)\n  - `MAX_FORM_PARTS` (max number of multipart fields)\n- MUST enforce additional limits at the reverse proxy / WSGI / platform level where possible.\n\nInsecure patterns:\n- Unlimited request body sizes when handling uploads or user content.\n- Accepting arbitrarily large multipart forms or many fields.\n\nDetection hints:\n- Inspect Flask config for these keys.\n- Inspect upload routes and APIs that accept large JSON.\n\nFix:\n- Set conservative defaults, override per-route only when needed.\n- Ensure large uploads use dedicated upload mechanisms.\n\n---\n\n### FLASK-HOST-001: Host header must be validated in production\nSeverity: Low (depends on app’s use of external URLs)\n\nRequired:\n- MUST set `TRUSTED_HOSTS` in production to restrict accepted Host values.\n- MUST NOT rely on `SERVER_NAME` as a host restriction mechanism.\n\nInsecure patterns:\n- `TRUSTED_HOSTS` unset in production.\n- Code that generates external URLs for emails/password resets without host validation.\n\nDetection hints:\n- Find `TRUSTED_HOSTS` config usage.\n- Find `url_for(..., _external=True)` and check how host is determined.\n\nFix:\n- Set `TRUSTED_HOSTS` to your expected domains (and required subdomains).\n- Ensure external URL generation uses trusted host/scheme.\n\n---\n\n### FLASK-PROXY-001: Reverse proxy trust must be configured correctly\nSeverity: Medium (High if relying on IPs for auth)\n\nRequired:\n- If behind a reverse proxy, MUST configure Flask/Werkzeug to trust forwarded headers only from the intended proxy.\n- MUST NOT blindly trust `X-Forwarded-*` headers from the open internet.\n\nInsecure patterns:\n- `ProxyFix` applied with overly broad trust settings, or applied without understanding how many proxies are in front.\n- Relying on forwarded headers for scheme/host without validation.\n\nDetection hints:\n- Search for `ProxyFix`.\n- Search for usage of `request.remote_addr`, `request.scheme`, `request.host` in security-sensitive logic.\n\nFix:\n- Configure `ProxyFix` (or platform-specific settings) with correct hop counts.\n- Keep `TRUSTED_HOSTS` in place even behind proxies.\n\n---\n\n### FLASK-PATH-001: Prevent path traversal and unsafe file serving\nSeverity: High\n\nRequired:\n- MUST NOT pass user-controlled file paths to `send_file` or to direct file I/O.\n- MUST use safe file serving patterns:\n  - `send_from_directory` for user-specified paths under a trusted base directory\n  - `safe_join` for joining a trusted base directory with untrusted path components\n  - `secure_filename` for uploaded filenames (and still generate your own unique storage name)\n- MUST ensure user uploads are not served as executable/active content (especially HTML).\n- SHOULD in general use `safe_join` over `os.path.join` for almost any filesystem path computations.\n\nInsecure patterns:\n- `send_file(request.args[\"path\"])`\n- `open(os.path.join(base_dir, user_path))` where `user_path` is untrusted\n- Serving uploads from within a static web root without restrictions\n\nDetection hints:\n- Search for `send_file(`, `open(`, `os.path.join(`, `pathlib.Path(...)/...` in file routes.\n- Identify where filenames come from (request args, DB, headers).\n\nFix:\n- Serve only from a non-user-controlled directory base.\n- Store uploads outside static roots; serve through controlled routes.\n- Always validate and normalize file identifiers.\n\nNote: `safe_join` is imported from `werkzeug.security`\n\n---\n\n### FLASK-UPLOAD-001: File uploads must be validated, stored safely, and served safely\nSeverity: High\n\nRequired:\n- MUST enforce upload size limits (app + edge).\n- MUST validate file type using allowlists and content checks (not only extension).\n- MUST store uploads outside executable/static roots when possible.\n- SHOULD generate server-side filenames (random IDs) and avoid trusting original names.\n- MUST serve potentially active formats safely (download attachment) unless explicitly intended.\n\nInsecure patterns:\n- Accepting arbitrary file types and serving them back inline.\n- Using user-supplied filename as storage path.\n- Missing size/type validation.\n\nDetection hints:\n- Look for `request.files[...]` handlers.\n- Check for `secure_filename` usage (and whether it’s combined with uniqueness).\n- Check where files are stored and how they are served.\n\nFix:\n- Implement allowlist validation + safe storage + safe serving.\n- Add scanning / quarantine if applicable.\n\n---\n\n### FLASK-INJECT-001: Prevent SQL injection (use parameterized queries / ORM)\nSeverity: High\n\nRequired:\n- MUST use parameterized queries or an ORM that parameterizes under the hood.\n- MUST NOT build SQL by string concatenation / f-strings with untrusted input.\n\nInsecure patterns:\n- `f\"SELECT ... WHERE id={request.args['id']}\"`\n- `\"... WHERE name = '%s'\" % user_input`\n\nDetection hints:\n- Grep for `SELECT`, `INSERT`, `UPDATE`, `DELETE` strings in Python code.\n- Track untrusted data into DB execute calls.\n\nFix:\n- Replace with parameterized queries or ORM query APIs.\n- Validate types (e.g., int IDs) before querying.\n\n---\n\n### FLASK-INJECT-002: Prevent OS command injection\nSeverity: Critical to High (depends on exposure)\n\nRequired:\n- MUST avoid executing shell commands with untrusted input.\n- If subprocess is necessary:\n  - MUST pass args as a list (not a string)\n  - MUST NOT use `shell=True` with attacker-influenced strings\n  - SHOULD use strict allowlists for any variable component\n- If possible, use pure python or a python library rather than using a subprocess or system command\n- Do not assume that arguments to commands will be inherently safe even in `shell=False`. Commands may incorrectly process these arguments as command line flags or other trusted values.\n\nInsecure patterns:\n- `os.system(user_input)`\n- `subprocess.run(f\"cmd {user}\", shell=True)`\n- Passing user strings into `bash -c`, `sh -c`, PowerShell, etc.\n\nDetection hints:\n- Search for `os.system`, `subprocess`, `Popen`, `shell=True`.\n- Trace data from request/DB into these calls.\n\nFix:\n- Use library APIs instead of shell commands.\n- If unavoidable, hard-code the command and allowlist validated parameters. If supported by the subcommand, try to keep user values after `--` to prevent them being processed as command line flags.\n\n---\n\n### FLASK-SSRF-001: Prevent server-side request forgery (SSRF) in outbound HTTP\nSeverity: Medium\n\n- Note: For small stand alone projects this is less important. It is most important when deploying into an LAN or with other services listening on the same server.\n\nRequired:\n- MUST treat outbound requests to user-provided URLs as high risk.\n- SHOULD validate and restrict destinations (allowlist hosts/domains) for any user-influenced URL fetch.\n- SHOULD block access to:\n  - localhost / private IP ranges / link-local addresses\n  - cloud metadata endpoints\n- MUST NOT allow non http/https protocols (ie file: etc)\n- SHOULD set timeouts and restrict redirects.\n\n\n\nInsecure patterns:\n- `requests.get(request.args[\"url\"])`\n- Webhooks/preview/fetch endpoints that accept arbitrary URLs.\n\nDetection hints:\n- Search for `requests.get/post`, `httpx`, `urllib`, `aiohttp` usage with untrusted URL sources.\n- Identify URL fetch features (preview, import, webhook tester).\n\nFix:\n- Ensure URLs are http or https (disallow file: or other protocols)\n- Enforce allowlists and network egress controls.\n- Add strict parsing and IP resolution checks; set timeouts; disable redirects if not needed.\n\n---\n\n### FLASK-REDIRECT-001: Prevent open redirects\nSeverity: Low\n\nRequired:\n- MUST validate redirect targets derived from untrusted input (e.g., `next`, `redirect`, `return_to`).\n- SHOULD use allowlists of internal paths or known domains.\n- SHOULD prefer redirecting only to same-site relative paths.\n\nInsecure patterns:\n- `redirect(request.args.get(\"next\"))` with no validation.\n\nDetection hints:\n- Search for `redirect(` and examine where `location` comes from.\n\nFix:\n- Only allow relative paths or allowlisted domains.\n- Fall back to a safe default if validation fails.\n\n---\n\n### FLASK-HTTP-001: Use HTTP methods safely; do not change state via GET; avoid secrets in URLs\nSeverity: Medium\n\nRequired:\n- MUST NOT perform state-changing actions over GET.\n- MUST NOT put secrets in URLs (query strings are commonly logged and leaked via referrers).\n- SHOULD require POST/PUT/PATCH/DELETE for state change and apply CSRF protections when cookie-authenticated.\n\nInsecure patterns:\n- `/delete?id=...` implemented as GET\n- Password reset tokens or API keys in query params\n\nDetection hints:\n- Enumerate GET routes and inspect whether they mutate state.\n- Look for URL parameters named `token`, `key`, `secret`, `password`, etc.\n\nFix:\n- Move state changes to non-GET methods.\n- Move sensitive values to secure channels (POST bodies, headers) and protect them.\n\n---\n\n### FLASK-CORS-001: CORS must be explicit and least-privilege\nSeverity: Medium (High if misconfigured with credentials)\n\nRequired:\n- If CORS is not needed, MUST keep it disabled.\n- If CORS is needed:\n  - MUST allowlist trusted origins (do not reflect arbitrary origins).\n  - MUST be careful with credentialed requests; do not combine broad origins with cookies.\n  - SHOULD restrict allowed methods and headers.\n\nInsecure patterns:\n- `Access-Control-Allow-Origin: *` paired with credentialed cookies or overly broad access.\n- Reflecting `Origin` without validation.\n- `flask_cors.CORS(app)` with permissive defaults.\n\nDetection hints:\n- Search for `flask_cors`, `CORS(`, `Access-Control-Allow-Origin`.\n- Check for `supports_credentials=True` and wildcard origins.\n\nFix:\n- Use a strict origin allowlist and minimal methods/headers.\n- Ensure cookie-authenticated endpoints are not exposed cross-origin unless necessary.\n\n---\n\n### FLASK-SUPPLY-001: Dependency and patch hygiene (focus on security-relevant deps)\nSeverity: Low\n\nRequired:\n- SHOULD pin and regularly update security-critical dependencies (Flask, Werkzeug, Jinja2, itsdangerous).\n- MUST respond to known security advisories promptly.\n\nAudit focus example:\n- If running on Windows and using file serving with untrusted paths, ensure Werkzeug’s `safe_join` behavior is not vulnerable to Windows device-name edge cases.\n\nDetection hints:\n- Check `requirements.txt`, lockfiles, and runtime environments.\n- Identify where security helpers are used (safe_join, send_from_directory).\n\nFix:\n- Upgrade to patched versions and add regression tests for the impacted behavior.\n\n--------------------------------------------------------------------\n\n## 5) Practical scanning heuristics (how to “hunt”)\n\nWhen actively scanning, use these high-signal patterns:\n\n- Dev server / debug:\n  - `app.run(`, `flask run`, `--debug`, `DEBUG=True`, `FLASK_DEBUG`\n- Secrets:\n  - `SECRET_KEY`, `secret_key`, `.env` committed, `print(config)`\n- Cookies / sessions:\n  - `SESSION_COOKIE_SECURE`, `SESSION_COOKIE_HTTPONLY`, `SESSION_COOKIE_SAMESITE`\n  - `session[...] =` with sensitive values\n- CSRF:\n  - POST/PUT/PATCH/DELETE handlers without CSRF checks in cookie-authenticated apps\n- XSS/SSTI:\n  - `Markup(`, `|safe`, unquoted attributes, `render_template_string`\n- Files:\n  - `send_file(` with user-controlled path; `open(` on user path; `os.path.join` with untrusted\n  - upload handlers using user filename for path\n- Injection:\n  - SQL strings + string formatting into `.execute(...)`\n  - `subprocess.*`, `shell=True`, `os.system`\n- SSRF:\n  - `requests.get/post` or `httpx` with URL from request/DB\n- Redirect:\n  - `redirect(request.args.get(\"next\"))`\n- CORS:\n  - `flask_cors.CORS` permissive configs; wildcard origins with credentials\n\nAlways try to confirm:\n- data origin (untrusted vs trusted)\n- sink type (template/SQL/subprocess/files/redirect/http)\n- protective controls present (validation, allowlists, middleware)\n\n--------------------------------------------------------------------\n\n## 6) Sources (accessed 2026-01-26)\n\nPrimary framework documentation:\n- Flask Docs: Deploying to Production — https://flask.palletsprojects.com/en/stable/deploying/\n- Flask Docs: Debugging Application Errors — https://flask.palletsprojects.com/en/stable/debugging/\n- Flask Docs: Configuration Handling — https://flask.palletsprojects.com/en/stable/config/\n- Flask Docs: Security Considerations — https://flask.palletsprojects.com/en/stable/web-security/\n- Flask Docs: Tell Flask it is Behind a Proxy — https://flask.palletsprojects.com/en/stable/deploying/proxy_fix/\n- Flask API Docs: Sessions — https://flask.palletsprojects.com/en/stable/api/#sessions\n\nWerkzeug documentation & advisories:\n- Werkzeug Docs: Utilities (send_file / send_from_directory / safe_join / secure_filename / password hashing) — https://werkzeug.palletsprojects.com/en/stable/utils/\n- GitHub Advisory: CVE-2025-66221 (Werkzeug safe_join Windows device names) — https://github.com/advisories/GHSA-hgf8-39gv-g3f2\n\nOWASP Cheat Sheet Series:\n- Session Management — https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html\n- CSRF Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html\n- XSS Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html\n- Input Validation — https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html\n- SQL Injection Prevention — https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html\n- Injection Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Injection_Prevention_Cheat_Sheet.html\n- OS Command Injection Defense — https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html\n- SSRF Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html\n- File Upload — https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html\n- Unvalidated Redirects — https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html\n- HTTP Headers — https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html\n\nTemplate safety references:\n- Jinja: Sandbox (rendering untrusted templates) — https://jinja.palletsprojects.com/en/stable/sandbox/\n- OWASP WSTG: Testing for Server-Side Template Injection — https://owasp.org/www-project-web-security-testing-guide/v41/4-Web_Application_Security_Testing/07-Input_Validation_Testing/18-Testing_for_Server_Side_Template_Injection\n- PortSwigger Web Security Academy: Server-side template injection — https://portswigger.net/web-security/server-side-template-injection\n\nHTTP semantics:\n- RFC 9110: HTTP Semantics (safe methods) — https://www.rfc-editor.org/rfc/rfc9110\n\n<!-- File: core/skills/builtin/security-best-practices/SKILL.md (Tokens: ~1663 | Category: anthropic-skill) -->\n---\nname: \"security-best-practices\"\ndescription: \"Perform language and framework specific security best-practice reviews and suggest improvements. Trigger only when the user explicitly requests security best practices guidance, a security review/report, or secure-by-default coding help. Trigger only for supported languages (python, javascript/typescript, go). Do not trigger for general code review, debugging, or non-security tasks.\"\n---\n\n# Security Best Practices\n\n## Overview\n\nThis skill provides a description of how to identify the language and frameworks used by the current context, and then to load information from this skill's references directory about the security best practices for this language and or frameworks.\n\nThis information, if present, can be used to write new secure by default code, or to passively detect major issues within existing code, or (if requested by the user) provide a vulnerability report and suggest fixes.\n\n## Workflow\n\nThe initial step for this skill is to identify ALL languages and ALL frameworks which you are being asked to use or already exist in the scope of the project you are working in. Focus on the primary core frameworks. Often you will want to identify both frontend and backend languages and frameworks.\n\nThen check this skill's references directory to see if there are any relevant documentation for the language and or frameworks. Make sure you read ALL reference files which relate to the specific framework or language. The format of the filenames is `<language>-<framework>-<stack>-security.md`. You should also check if there is a `<language>-general-<stack>-security.md` which is agnostic to the framework you may be using.\n\nIf working on a web application which includes a frontend and a backend, make sure you have checked for reference documents for BOTH the frontend and backend!\n\nIf you are asked to make a web app which will include both a frontend and backend, but the frontend framework is not specified, also check out `javascript-general-web-frontend-security.md`. It is important that you understand how to secure both the frontend and backend.\n\nIf no relevant information is available in the skill's references directory, think a little bit about what you know about the language, the framework, and all well known security best practices for it. If you are unsure you can try to search online for documentation on security best practices.\n\nFrom there it can operate in a few ways.\n\n1. The primary mode is to just use the information to write secure by default code from this point forward. This is useful for starting a new project or when writing new code.\n\n2. The secondary mode is to passively detect vulnerabilities while working in the project and writing code for the user. Critical or very important vulnerabilities or major issues going against security guidance can be flagged and the user can be told about them. This passive mode should focus on the largest impact vulnerabilities and secure defaults.\n\n3. The user can ask for a security report or to improve the security of the codebase. In this case a full report should be produced describe anyways the project fails to follow security best practices guidance. The report should be prioritized and have clear sections of severity and urgency. Then offer to start working on fixes for these issues. See #fixes below.\n\n## Workflow Decision Tree\n\n- If the language/framework is unclear, inspect the repo to determine it and list your evidence.\n- If matching guidance exists in `references/`, load only the relevant files and follow their instructions.\n- If no matching guidance exists, consider if you know any well known security best practices for the chosen language and or frameworks, but if asked to generate a report, let the user know that concrete guidance is not available (you can still generate the report or detect for sure critical vulnerabilities)\n\n# Overrides\n\nWhile these references contain the security best practices for languages and frameworks, customers may have cases where they need to bypass or override these practices. Pay attention to specific rules and instructions in the project's documentation and prompt files which may require you to override certain best practices. When overriding a best practice, you MAY report it to the user, but do not fight with them. If a security best practice needs to be bypassed / ignored for some project specific reason, you can also suggest to add documentation about this to the project so it is clear why the best practice is not being followed and to follow that bypass in the future.\n\n# Report Format\n\nWhen producing a report, you should write the report as a markdown file in `security_best_practices_report.md` or some other location if provided by the user. You can ask the user where they would like the report to be written to.\n\nThe report should have a short executive summary at the top.\n\nThe report should be clearly delineated into multiple sections based on severity of the vulnerability. The report should focus on the most critical findings as these have the highest impact for the user. All findings should be noted with an numeric ID to make them easier to reference.\n\nFor critical findings include a one sentence impact statement.\n\nOnce the report is written, also report it to the user directly, although you may be less verbose. You can offer to explain any of the findings or the reasons behind the security best practices guidance if the user wants more info on any findings.\n\nImportant: When referencing code in the report, make sure to find and include line numbers for the code you are referencing.\n\nAfter you write the report file, summarize the findings to the user.\n\nAlso tell the user where the final report was written to\n\n# Fixes\n\nIf you produced a report, let the user read the report and ask to begin performing fixes.\n\nIf you passively found a critical finding, notify the user and ask if they would like you to fix this finding.\n\nWhen producing fixes, focus on fixing a single finding at a time. The fixes should have concise clear comments explaining that the new code is based on the specific security best practice, and perhaps a very short reason why it would be dangerous to not do it in this way.\n\nAlways consider if the changes you want to make will impact the functionality of the user's code. Consider if the changes may cause regressions with how the project works currently. It is often the case that insecure code is relied on for other reasons (and this is why insecure code lives on for so long). Avoid breaking the user's project as this may make them not want to apply security fixes in the future. It is better to write a well thought out, well informed by the rest of the project, fix, then a quick slapdash change.\n\nAlways follow any normal change or commit flow the user has configured. If making git commits, provide clear commit messages explaining this is to align with security best practices. Try to avoid bunching a number of unrelated findings into a single commit.\n\nAlways follow any normal testing flows the user has configured (if any) to confirm that your changes are not introducing regressions. Consider the second order impacts the changes may have and inform the user before making them if there are any.\n\n# General Security Advice\n\nBelow is a few bits of secure coding advice that applies to almost any language or framework.\n\n### Avoid Using Incrementing IDs for Public IDs of Resources\n\nWhen assigning an ID for some resource, which will then be used by exposed to the internet, avoid using small auto-incrementing IDs. Use longer, random UUID4 or random hex string instead. This will prevent users from learning the quantity of a resource and being able to guess resource IDs.\n\n### A note on TLS\n\nWhile TLS is important for production deployments, most development work will be with TLS disabled or provided by some out-of-scope TLS proxy. Due to this, be very careful about not reporting lack of TLS as a security issue. Also be very careful around use of \"secure\" cookies. They should only be set if the application will actually be over TLS. If they are set on non-TLS applications (such as when deployed for local dev or testing), it will break the application. You can provide a env or other flag to override setting secure as a way to keep it off until on a TLS production deployment. Additionally avoid recommending HSTS. It is dangerous to use without full understanding of the lasting impacts (can cause major outages and user lockout) and it is not generally recommended for the scope of projects being reviewed by codex.\n\n<!-- File: core/skills/builtin/security-ownership-map/agents/openai.yaml (Tokens: ~50 | Category: anthropic-skill) -->\ninterface:\n  display_name: \"Security Ownership Map\"\n  short_description: \"Map maintainers, bus factor, and sensitive code ownership\"\n  default_prompt: \"Build a security ownership map for this repository and identify bus-factor risks in sensitive code.\"\n\n<!-- File: core/skills/builtin/security-ownership-map/references/neo4j-import.md (Tokens: ~665 | Category: anthropic-skill) -->\n# Neo4j Import Notes\n\nUse these steps when persisting the ownership graph to Neo4j.\n\n## Quick import (LOAD CSV)\n\n1. Copy `people.csv`, `files.csv`, and `edges.csv` into the Neo4j import directory.\n2. Run the following Cypher from Neo4j Browser or `cypher-shell`:\n\n```cypher\nCREATE CONSTRAINT person_id IF NOT EXISTS FOR (p:Person) REQUIRE p.id IS UNIQUE;\nCREATE CONSTRAINT file_id IF NOT EXISTS FOR (f:File) REQUIRE f.id IS UNIQUE;\n\nLOAD CSV WITH HEADERS FROM 'file:///people.csv' AS row\nMERGE (p:Person {id: row.person_id})\nSET p.name = row.name,\n    p.email = row.email,\n    p.first_seen = row.first_seen,\n    p.last_seen = row.last_seen,\n    p.commit_count = toInteger(row.commit_count),\n    p.touches = toInteger(row.touches),\n    p.sensitive_touches = toFloat(row.sensitive_touches),\n    p.primary_tz_offset = CASE row.primary_tz_offset WHEN '' THEN null ELSE row.primary_tz_offset END,\n    p.primary_tz_minutes = CASE row.primary_tz_minutes WHEN '' THEN null ELSE toInteger(row.primary_tz_minutes) END,\n    p.timezone_offsets = CASE row.timezone_offsets WHEN '' THEN null ELSE row.timezone_offsets END;\n\nLOAD CSV WITH HEADERS FROM 'file:///files.csv' AS row\nMERGE (f:File {id: row.file_id})\nSET f.path = row.path,\n    f.first_seen = row.first_seen,\n    f.last_seen = row.last_seen,\n    f.commit_count = toInteger(row.commit_count),\n    f.touches = toInteger(row.touches),\n    f.bus_factor = toInteger(row.bus_factor),\n    f.sensitivity_score = toFloat(row.sensitivity_score),\n    f.sensitivity_tags = row.sensitivity_tags;\n\nLOAD CSV WITH HEADERS FROM 'file:///edges.csv' AS row\nMATCH (p:Person {id: row.person_id})\nMATCH (f:File {id: row.file_id})\nMERGE (p)-[r:TOUCHES]->(f)\nSET r.touches = toInteger(row.touches),\n    r.recency_weight = toFloat(row.recency_weight),\n    r.first_seen = row.first_seen,\n    r.last_seen = row.last_seen,\n    r.sensitive_weight = toFloat(row.sensitive_weight);\n\nLOAD CSV WITH HEADERS FROM 'file:///cochange_edges.csv' AS row\nMATCH (f1:File {id: row.file_a})\nMATCH (f2:File {id: row.file_b})\nMERGE (f1)-[r:COCHANGES]->(f2)\nSET r.cochange_count = toInteger(row.cochange_count),\n    r.jaccard = toFloat(row.jaccard);\n```\n\n## Visualization tips\n\n- Use Neo4j Bloom or Browser with `MATCH (p:Person)-[r:TOUCHES]->(f:File) RETURN p,r,f`.\n- Filter by `f.sensitivity_score > 0` to highlight security-relevant clusters.\n- For Gephi, import `edges.csv` as edges and `files.csv` / `people.csv` as nodes.\n\n<!-- File: core/skills/builtin/security-ownership-map/SKILL.md (Tokens: ~2083 | Category: anthropic-skill) -->\n---\nname: \"security-ownership-map\"\ndescription: \"Analyze git repositories to build a security ownership topology (people-to-file), compute bus factor and sensitive-code ownership, and export CSV/JSON for graph databases and visualization. Trigger only when the user explicitly wants a security-oriented ownership or bus-factor analysis grounded in git history (for example: orphaned sensitive code, security maintainers, CODEOWNERS reality checks for risk, sensitive hotspots, or ownership clusters). Do not trigger for general maintainer lists or non-security ownership questions.\"\n---\n\n# Security Ownership Map\n\n## Overview\n\nBuild a bipartite graph of people and files from git history, then compute ownership risk and export graph artifacts for Neo4j/Gephi. Also build a file co-change graph (Jaccard similarity on shared commits) to cluster files by how they move together while ignoring large, noisy commits.\n\n## Requirements\n\n- Python 3\n- `networkx` (required; community detection is enabled by default)\n\nInstall with:\n\n```bash\npip install networkx\n```\n\n## Workflow\n\n1. Scope the repo and time window (optional `--since/--until`).\n2. Decide sensitivity rules (use defaults or provide a CSV config).\n3. Build the ownership map with `scripts/run_ownership_map.py` (co-change graph is on by default; use `--cochange-max-files` to ignore supernode commits).\n4. Communities are computed by default; graphml output is optional (`--graphml`).\n5. Query the outputs with `scripts/query_ownership.py` for bounded JSON slices.\n6. Persist and visualize (see `references/neo4j-import.md`).\n\nBy default, the co-change graph ignores common “glue” files (lockfiles, `.github/*`, editor config) so clusters reflect actual code movement instead of shared infra edits. Override with `--cochange-exclude` or `--no-default-cochange-excludes`. Dependabot commits are excluded by default; override with `--no-default-author-excludes` or add patterns via `--author-exclude-regex`.\n\nIf you want to exclude Linux build glue like `Kbuild` from co-change clustering, pass:\n\n```bash\npython skills/skills/security-ownership-map/scripts/run_ownership_map.py \\\n  --repo /path/to/linux \\\n  --out ownership-map-out \\\n  --cochange-exclude \"**/Kbuild\"\n```\n\n## Quick start\n\nRun from the repo root:\n\n```bash\npython skills/skills/security-ownership-map/scripts/run_ownership_map.py \\\n  --repo . \\\n  --out ownership-map-out \\\n  --since \"12 months ago\" \\\n  --emit-commits\n```\n\nDefaults: author identity, author date, and merge commits excluded. Use `--identity committer`, `--date-field committer`, or `--include-merges` if needed.\n\nExample (override co-change excludes):\n\n```bash\npython skills/skills/security-ownership-map/scripts/run_ownership_map.py \\\n  --repo . \\\n  --out ownership-map-out \\\n  --cochange-exclude \"**/Cargo.lock\" \\\n  --cochange-exclude \"**/.github/**\" \\\n  --no-default-cochange-excludes\n```\n\nCommunities are computed by default. To disable:\n\n```bash\npython skills/skills/security-ownership-map/scripts/run_ownership_map.py \\\n  --repo . \\\n  --out ownership-map-out \\\n  --no-communities\n```\n\n## Sensitivity rules\n\nBy default, the script flags common auth/crypto/secret paths. Override by providing a CSV file:\n\n```\n# pattern,tag,weight\n**/auth/**,auth,1.0\n**/crypto/**,crypto,1.0\n**/*.pem,secrets,1.0\n```\n\nUse it with `--sensitive-config path/to/sensitive.csv`.\n\n## Output artifacts\n\n`ownership-map-out/` contains:\n\n- `people.csv` (nodes: people)\n- `files.csv` (nodes: files)\n- `edges.csv` (edges: touches)\n- `cochange_edges.csv` (file-to-file co-change edges with Jaccard weight; omitted with `--no-cochange`)\n- `summary.json` (security ownership findings)\n- `commits.jsonl` (optional, if `--emit-commits`)\n- `communities.json` (computed by default from co-change edges when available; includes `maintainers` per community; disable with `--no-communities`)\n- `cochange.graph.json` (NetworkX node-link JSON with `community_id` + `community_maintainers`; falls back to `ownership.graph.json` if no co-change edges)\n- `ownership.graphml` / `cochange.graphml` (optional, if `--graphml`)\n\n`people.csv` includes timezone detection based on author commit offsets: `primary_tz_offset`, `primary_tz_minutes`, and `timezone_offsets`.\n\n## LLM query helper\n\nUse `scripts/query_ownership.py` to return small, JSON-bounded slices without loading the full graph into context.\n\nExamples:\n\n```bash\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out people --limit 10\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out files --tag auth --bus-factor-max 1\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out person --person alice@corp --limit 10\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out file --file crypto/tls\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out cochange --file crypto/tls --limit 10\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out summary --section orphaned_sensitive_code\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out community --id 3\n```\n\nUse `--community-top-owners 5` (default) to control how many maintainers are stored per community.\n\n## Basic security queries\n\nRun these to answer common security ownership questions with bounded output:\n\n```bash\n# Orphaned sensitive code (stale + low bus factor)\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out summary --section orphaned_sensitive_code\n\n# Hidden owners for sensitive tags\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out summary --section hidden_owners\n\n# Sensitive hotspots with low bus factor\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out summary --section bus_factor_hotspots\n\n# Auth/crypto files with bus factor <= 1\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out files --tag auth --bus-factor-max 1\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out files --tag crypto --bus-factor-max 1\n\n# Who is touching sensitive code the most\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out people --sort sensitive_touches --limit 10\n\n# Co-change neighbors (cluster hints for ownership drift)\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out cochange --file path/to/file --min-jaccard 0.05 --limit 20\n\n# Community maintainers (for a cluster)\npython skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out community --id 3\n\n# Monthly maintainers for the community containing a file\npython skills/skills/security-ownership-map/scripts/community_maintainers.py \\\n  --data-dir ownership-map-out \\\n  --file network/card.c \\\n  --since 2025-01-01 \\\n  --top 5\n\n# Quarterly buckets instead of monthly\npython skills/skills/security-ownership-map/scripts/community_maintainers.py \\\n  --data-dir ownership-map-out \\\n  --file network/card.c \\\n  --since 2025-01-01 \\\n  --bucket quarter \\\n  --top 5\n```\n\nNotes:\n- Touches default to one authored commit (not per-file). Use `--touch-mode file` to count per-file touches.\n- Use `--window-days 90` or `--weight recency --half-life-days 180` to smooth churn.\n- Filter bots with `--ignore-author-regex '(bot|dependabot)'`.\n- Use `--min-share 0.1` to show stable maintainers only.\n- Use `--bucket quarter` for calendar quarter groupings.\n- Use `--identity committer` or `--date-field committer` to switch from author attribution.\n- Use `--include-merges` to include merge commits (excluded by default).\n\n### Summary format (default)\n\nUse this structure, add fields if needed:\n\n```json\n{\n  \"orphaned_sensitive_code\": [\n    {\n      \"path\": \"crypto/tls/handshake.rs\",\n      \"last_security_touch\": \"2023-03-12T18:10:04+00:00\",\n      \"bus_factor\": 1\n    }\n  ],\n  \"hidden_owners\": [\n    {\n      \"person\": \"alice@corp\",\n      \"controls\": \"63% of auth code\"\n    }\n  ]\n}\n```\n\n## Graph persistence\n\nUse `references/neo4j-import.md` when you need to load the CSVs into Neo4j. It includes constraints, import Cypher, and visualization tips.\n\n## Notes\n\n- `bus_factor_hotspots` in `summary.json` lists sensitive files with low bus factor; `orphaned_sensitive_code` is the stale subset.\n- If `git log` is too large, narrow with `--since` or `--until`.\n- Compare `summary.json` against CODEOWNERS to highlight ownership drift.\n\n<!-- File: core/skills/builtin/security-threat-model/agents/openai.yaml (Tokens: ~51 | Category: anthropic-skill) -->\ninterface:\n  display_name: \"Security Threat Model\"\n  short_description: \"Repo-grounded threat modeling and abuse-path analysis\"\n  default_prompt: \"Create a repository-grounded threat model for this codebase with prioritized abuse paths and mitigations.\"\n\n<!-- File: core/skills/builtin/security-threat-model/references/prompt-template.md (Tokens: ~2676 | Category: anthropic-skill) -->\n# Threat Modeling Prompt Template for LLMs\n\nThis reference provides a disciplined, repo-grounded prompt that produces AppSec-usable threat models. Use it when you need a reliable output contract and a consistent process to assemble the threat model output\n\n## System prompt\n\nUse this as a stable system prompt:\n\n````text\nYou are a senior application security engineer producing a threat model that will be read by other AppSec engineers.\n\nPrimary objective:\n- Generate a threat model that is specific to THIS repository and its real-world usage.\n- Prefer concrete, evidence-backed findings over generic vulnerability checklists.\n\nEvidence and grounding rules:\n- Do not invent components, data stores, endpoints, flows, or controls.\n- Every architectural claim must be backed by at least one \"Evidence anchor\" referencing a repo path\n  (and a symbol name, config key, or a short quoted snippet if available).\n- If information is missing, state assumptions explicitly and list the open questions needed to validate them.\n\nSecurity hygiene:\n- Never output secrets. If you encounter tokens/keys/passwords, redact them and only describe their presence and location.\n\nThreat modeling approach:\n- Model the system using data flows and trust boundaries.\n- Enumerate threats and produce attack goals and abuse paths\n- Prioritize threats using explicit likelihood and impact reasoning (qualitative is acceptable: low/medium/high).\n\nScope discipline:\n- Clearly separate: production/runtime behavior vs CI/build/dev tooling vs tests/examples.\n- Clearly separate attacker-controlled inputs vs operator-controlled inputs vs developer-controlled inputs.\n- If a vulnerability class requires attacker control that likely does not exist for this repo's real usage, say so and downgrade severity.\n\nCommunication quality:\n- Write for AppSec engineers: concise but specific.\n- Use precise terminology. Include mitigations and residual risks.\n- Avoid restating large blocks of README/spec; summarize and point to evidence.\n\nDiagram requirements:\n- Produce a single compact Mermaid flowchart showing primary components and trust boundaries.\n- Mermaid must render cleanly. Use a conservative subset:\n  - Use `flowchart TD` or `flowchart LR` and only `-->` arrows.\n  - Use simple node IDs (letters/numbers/underscores only) and quoted labels (e.g., `A[\"Label\"]`); avoid `A(Label)` shape syntax.\n  - Do not use Mermaid `title` lines or `style` directives.\n  - Keep edge labels to plain words/spaces only via `-->|label|`; avoid `{}`, `[]`, `()`, or quotes in edge labels (if needed, drop the label).\n  - Keep node labels short and readable: do not include file paths, URLs, or socket paths (put those details in prose outside the diagram).\n- Wrap the diagram in a Markdown fenced block:\n  ```mermaid\n  <mermaid syntax here>\n  ```\n````\n\n## Repository summary prompt\n\n```\nWe have a codebase located at {repo_directory/path}, currently on branch {branch_name}.\n\nPlease produce a security-oriented summary of the repository (or the specified sub-path) with the goal of helping a follow-on security engineer quickly understand the system well enough to build an initial threat model and investigate potential security hypotheses.\n\nObjectives\n1.\tProject overview\n\t•\tIdentify the primary programming languages, frameworks, and build system.\n\t•\tSummarize the project’s core purpose and high-level architecture.\n\t•\tDescribe major components, services, or modules and how they interact.\n2.\tSecurity posture and entry points\n\t•\tIdentify likely user entry points and trust boundaries.\n\t•\tDescribe existing security layers (e.g., authentication, authorization, validation, sandboxing, isolation, privilege boundaries).\n\t•\tCall out security-critical components and assumptions that must hold for the system to remain secure.\n\nGuidance for Security Analysis\n\nStructure the summary so an application security engineer can quickly answer questions such as:\n\t•\tWhere does user input originate?\n\t•\tHow is untrusted data parsed, validated, and handled?\n\t•\tWhat security assumptions should not be violated?\n\t•\tWhere are the most likely choke points for security bugs?\n\nAdapt the analysis to the project type. For example:\n\t•\tWeb applications: where requests enter, how user data is parsed, routed, authenticated, and stored.\n\t•\tCommand-line tools: supported inputs (arguments, files, environment variables, stdin) and how they are processed.\n\t•\tNetwork daemons: exposed ports, supported protocols, message formats, and request handling paths.\n\t•\tOperating system or low-level components: common vulnerability classes (e.g., memory corruption, logic flaws) that could lead to LPE or RCE.\n\nBe thorough but pragmatic: the goal is to help a security engineer quickly determine whether a discovered bug is security-relevant and where deeper investigation should focus.\n\nTooling Notes\n\nIf Ripgrep (rg) is available, use it to explore the codebase. When using grep or rg, always include the -I flag to avoid searching through binary files.\n```\n\n\n\n## User prompt template\n\nUse this as the task prompt, filling in what you know and marking the rest as assumptions:\n\n```text\n# Inputs\nContext (fill as available; otherwise infer and mark assumptions):\n- intended_usage: {intended_usage}\n- deployment_model: {deployment_model}\n- data_sensitivity: {data_sensitivity}\n- internet_exposure: {internet_exposure}\n- authn_authz_expectations: {authn_authz_expectations}\n- out_of_scope: {out_of_scope}\n\nProvided summaries (may be incomplete):\n- repository_summary: {repository_summary}\n\n\nIn-scope code locations (if known):\n- in_scope_paths: {in_scope_paths}\n\n# Task\nConstruct a repo-centric threat model that helps AppSec engineers understand the most important security risks and where to focus manual review.\n\nYou MUST follow this process and reflect outputs in the final document:\n\n## Process\n1) Repo discovery (evidence collection)\n   a. Identify the repo shape:\n      - languages and frameworks\n      - how it runs (server/cli/library), entrypoints, build artifacts\n   b. Identify security-relevant surfaces and controls by searching for evidences, such as:\n      - network listeners/routes/endpoints; RPC handlers; message consumers\n      - authentication, session/token handling, authorization checks, RBAC/ACL logic\n      - parsing/serialization/deserialization (JSON/YAML/XML/protobuf), template rendering, eval/dynamic code\n      - file upload/read paths, archive extraction, image/document parsing\n      - database/queue/cache clients and query construction\n      - secrets/config loading, environment variables, key management\n      - SSRF-capable HTTP clients, webhooks, URL fetchers\n      - sandboxing/isolation, privilege boundaries, subprocess execution\n      - logging/auditing and error handling paths\n      - CI/build/release: pipelines, dependency management, artifact publishing\n\n2) System model\n   a. Summarize the primary components (runtime plus critical build/CI components when relevant).\n   b. Enumerate data flows and trust boundaries.\n      - For each trust boundary, specify:\n        * source to destination\n        * data types crossing (e.g., credentials, PII, files, tokens, prompts)\n        * channel/protocol (HTTP/gRPC/IPC/file/db)\n        * security guarantees and validation (auth, mTLS, origin checks, schema validation, rate limits)\n   c. Provide a compact Mermaid diagram showing components and trust boundaries.\n\n3) Assets and security objectives\n   - List assets (data, credentials, integrity-critical state, availability-critical components, build artifacts).\n   - For each asset, state why it matters (confidentiality/integrity/availability, compliance, user harm).\n\n4) Attacker model\n   - Capabilities: realistic remote attacker assumptions based on intended usage and exposure.\n   - Non-capabilities: things attacker cannot plausibly do (unless explicitly in scope), to avoid inflated severity.\n\n5) Threat enumeration (concrete, system-specific)\n   - Generate threats as attacker stories tied to:\n     * entry points\n     * trust boundaries\n     * privileged components\n   - Prefer abuse paths (multi-step sequences) over single-line generic threats.\n\n6) Risk prioritization\n   - For each threat:\n     * Likelihood: low/medium/high with a 1 to 2 sentence justification\n     * Impact: low/medium/high with a 1 to 2 sentence justification\n     * Overall priority: critical/high/medium/low (based on likelihood x impact, adjusted for existing controls)\n   - Explicitly state which assumptions most affect risk.\n\n7) Validate assumptions and service context with the user (required before final report)\n   - Summarize key assumptions that materially affect scope or risk ranking.\n   - Ask 1 to 3 targeted questions to resolve missing service meta-context (service owner/environment, scale/users, deployment model, authn/authz, internet exposure, data sensitivity, multi-tenancy).\n   - Pause and wait for user feedback before producing the final report.\n   - If the user cannot answer, proceed with explicit assumptions and mark any conditional conclusions.\n\n8) Mitigations and recommendations\n   - For each high/critical threat:\n     * Existing mitigations (with evidence anchors)\n     * Gaps/weaknesses\n     * Recommended mitigations (code/config/process)\n     * Detection/monitoring ideas (logging, metrics, alerts)\n\n9) Focus paths for manual security review\n   - Output 2 to 30 repo-relative paths (files or directories) that merit deeper review.\n   - For each path, give a one-sentence reason tied to the threat model.\n\n10) Quality check\n   - Provide a short checklist confirming you covered:\n     * all entry points you discovered\n     * each trust boundary at least once in threats\n     * runtime vs CI/dev separation\n     * user clarifications (or explicit non-responses)\n     * assumptions and open questions\n\n## Required output format (exact)\nBefore producing the final Markdown report, first provide an assumption-validation check-in:\n- List the key assumptions in 3 to 6 bullets.\n- Ask 1 to 3 targeted context questions.\n- Wait for the user response, then produce the final report below using the clarified context.\n\nProduce valid Markdown with these sections in this order:\n\n## Executive summary\n- 1 short paragraph on the top risk themes and highest-risk areas.\n\n## Scope and assumptions\n- In-scope paths, out-of-scope items, and explicit assumptions.\n- A short list of open questions that would materially change the risk ranking.\n\n\n## System model\n### Primary components\n### Data flows and trust boundaries\nRepresent the system as a sequence of arrow-style bullets (e.g., Internet → API Server, User Input -> Application Logic, etc). For each boundary, document:\n\t•\tthe primary data types crossing the boundary,\n\t•\tthe communication channel or protocol,\n\t•\tthe security guarantees (e.g., authentication, origin checks, encryption, rate limiting), and\n\t•\tany input validation, normalization, or schema enforcement performed.\n\n#### Diagram\n- Include a single, compact Mermaid diagram (`flowchart TD` or `flowchart LR`) showing primary components and trust boundaries (e.g., separate trust zones via subgraphs). Keep it compact, use only `-->`, avoid `title`/`style`, keep node labels short (no paths/URLs), and keep edge labels to plain words only (avoid `{}`, `[]`, `()`, or quotes).\n\n\n## Assets and security objectives\n- A table: Asset | Why it matters | Security objective (C/I/A)\n\n## Attacker model\n### Capabilities\n### Non-capabilities\n\n## Entry points and attack surfaces\n- A table: Surface | How reached | Trust boundary | Notes | Evidence (repo path / symbol)\n\n## Top abuse paths\n- 5 to 10 short abuse paths, each as a numbered sequence of steps (attacker goal -> steps -> impact).\n\n## Threat model table\n- A Markdown table with columns:\n  Threat ID | Threat source | Prerequisites | Threat action | Impact | Impacted assets | Existing controls (evidence) | Gaps | Recommended mitigations | Detection ideas | Likelihood | Impact severity | Priority\n\nRules:\n- Threat IDs must be stable and formatted: TM-001, TM-002, ...\n- Priority must be one of: critical, high, medium, low.\n- Keep prerequisites to 1 to 2 sentences. Keep recommended mitigations concrete.\n\n## Criticality calibration\n- Define what counts as critical/high/medium/low for THIS repo and context.\n- Include 2 to 3 examples per level (tailored to the repo's assets and exposure).\n\n## Focus paths for security review\n- A table: Path | Why it matters | Related Threat IDs\n\n## Notes on use\n\n- Fill in known context, but allow the model to infer and mark assumptions.\n- Include 1–2 repo-path anchors per major claim; do not dump every match.\n\n<!-- File: core/skills/builtin/security-threat-model/references/security-controls-and-assets.md (Tokens: ~378 | Category: anthropic-skill) -->\n# Security Controls and Asset Categories\n\nUse this as a lightweight checklist to keep outputs consistent across teams. Prefer concrete, system-specific items over generic text.\n\n## Asset categories (pick only what applies)\n- User data (PII, content, uploads)\n- Authentication artifacts (passwords, tokens, sessions, cookies)\n- Authorization state (roles, policies, ACLs)\n- Secrets and keys (API keys, signing keys, encryption keys)\n- Configuration and feature flags\n- Models and weights (if ML systems)\n- Source code and build artifacts\n- Audit logs and telemetry\n- Availability-critical resources (queues, caches, rate limits, compute budgets)\n- Tenant isolation boundaries and metadata\n\n## Security control categories\n- Identity and access: authN, authZ, session handling, mTLS, key rotation\n- Input protection: schema validation, parsing hardening, upload scanning, sandboxing\n- Network safeguards: TLS, network policies, WAF, rate limiting, DoS controls\n- Data protection: encryption at rest/in transit, tokenization, redaction\n- Isolation: process sandboxing, container boundaries, tenant isolation, seccomp\n- Observability: audit logs, alerting, anomaly detection, tamper resistance\n- Supply chain: dependency pinning, SBOMs, provenance, signing\n- Change control: CI checks, deployment approvals, config guardrails\n\n## Mitigation phrasing patterns\n- \"Enforce schema at <boundary> for <payload> before <component>.\"\n- \"Require authZ check for <action> on <resource> in <service>.\"\n- \"Isolate <parser/component> in a sandbox with <resource limits>.\"\n- \"Rate limit <endpoint> by <key> and apply burst caps.\"\n- \"Encrypt <data> at rest using <key management> and rotate <keys>.\"\n\n<!-- File: core/skills/builtin/security-threat-model/SKILL.md (Tokens: ~1112 | Category: anthropic-skill) -->\n---\nname: \"security-threat-model\"\ndescription: \"Repository-grounded threat modeling that enumerates trust boundaries, assets, attacker capabilities, abuse paths, and mitigations, and writes a concise Markdown threat model. Trigger only when the user explicitly asks to threat model a codebase or path, enumerate threats/abuse paths, or perform AppSec threat modeling. Do not trigger for general architecture summaries, code review, or non-security design work.\"\n---\n\n# Threat Model Source Code Repo\n\nDeliver an actionable AppSec-grade threat model that is specific to the repository or a project path, not a generic checklist. Anchor every architectural claim to evidence in the repo and keep assumptions explicit. Prioritizing realistic attacker goals and concrete impacts over generic checklists.\n\n## Quick start\n\n1) Collect (or infer) inputs:\n- Repo root path and any in-scope paths.\n- Intended usage, deployment model, internet exposure, and auth expectations (if known).\n- Any existing repository summary or architecture spec.\n- Use prompts in `references/prompt-template.md` to generate a repository summary.\n- Follow the required output contract in `references/prompt-template.md`. Use it verbatim when possible.\n\n## Workflow\n\n### 1) Scope and extract the system model\n- Identify primary components, data stores, and external integrations from the repo summary.\n- Identify how the system runs (server, CLI, library, worker) and its entrypoints.\n- Separate runtime behavior from CI/build/dev tooling and from tests/examples.\n- Map the in-scope locations to those components and exclude out-of-scope items explicitly.\n- Do not claim components, flows, or controls without evidence.\n\n### 2) Derive boundaries, assets, and entry points\n- Enumerate trust boundaries as concrete edges between components, noting protocol, auth, encryption, validation, and rate limiting.\n- List assets that drive risk (data, credentials, models, config, compute resources, audit logs).\n- Identify entry points (endpoints, upload surfaces, parsers/decoders, job triggers, admin tooling, logging/error sinks).\n\n### 3) Calibrate assets and attacker capabilities\n- List the assets that drive risk (credentials, PII, integrity-critical state, availability-critical components, build artifacts).\n- Describe realistic attacker capabilities based on exposure and intended usage.\n- Explicitly note non-capabilities to avoid inflated severity.\n\n\n### 4) Enumerate threats as abuse paths\n- Prefer attacker goals that map to assets and boundaries (exfiltration, privilege escalation, integrity compromise, denial of service).\n- Classify each threat and tie it to impacted assets.\n- Keep the number of threats small but high quality.\n\n### 5) Prioritize with explicit likelihood and impact reasoning\n- Use qualitative likelihood and impact (low/medium/high) with short justifications.\n- Set overall priority (critical/high/medium/low) using likelihood x impact, adjusted for existing controls.\n- State which assumptions most influence the ranking.\n\n### 6) Validate service context and assumptions with the user\n- Summarize key assumptions that materially affect threat ranking or scope, then ask the user to confirm or correct them.\n- Ask 1–3 targeted questions to resolve missing context (service owner and environment, scale/users, deployment model, authn/authz, internet exposure, data sensitivity, multi-tenancy).\n- Pause and wait for user feedback before producing the final report.\n- If the user declines or can’t answer, state which assumptions remain and how they influence priority.\n\n### 7) Recommend mitigations and focus paths\n- Distinguish existing mitigations (with evidence) from recommended mitigations.\n- Tie mitigations to concrete locations (component, boundary, or entry point) and control types (authZ checks, input validation, schema enforcement, sandboxing, rate limits, secrets isolation, audit logging).\n- Prefer specific implementation hints over generic advice (e.g., \"enforce schema at gateway for upload payloads\" vs \"validate inputs\").\n- Base recommendations on validated user context; if assumptions remain unresolved, mark recommendations as conditional.\n\n### 8) Run a quality check before finalizing\n- Confirm all discovered entrypoints are covered.\n- Confirm each trust boundary is represented in threats.\n- Confirm runtime vs CI/dev separation.\n- Confirm user clarifications (or explicit non-responses) are reflected.\n- Confirm assumptions and open questions are explicit.\n- Confirm that the format of the report matches closely the required output format defined in prompt template: `references/prompt-template.md`\n- Write the final Markdown to a file named `<repo-or-dir-name>-threat-model.md` (use the basename of the repo root, or the in-scope directory if you were asked to model a subpath).\n\n\n## Risk prioritization guidance (illustrative, not exhaustive)\n- High: pre-auth RCE, auth bypass, cross-tenant access, sensitive data exfiltration, key or token theft, model or config integrity compromise, sandbox escape.\n- Medium: targeted DoS of critical components, partial data exposure, rate-limit bypass with measurable impact, log/metrics poisoning that affects detection.\n- Low: low-sensitivity info leaks, noisy DoS with easy mitigation, issues requiring unlikely preconditions.\n\n## References\n\n- Output contract and full prompt template: `references/prompt-template.md`\n- Optional controls/asset list: `references/security-controls-and-assets.md`\n\nOnly load the reference files you need. Keep the final result concise, grounded, and reviewable.\n\n<!-- File: core/skills/builtin/skill-creator/agents/openai.yaml (Tokens: ~41 | Category: anthropic-skill) -->\ninterface:\n  display_name: \"Skill Creator\"\n  short_description: \"Create or update a skill\"\n  default_prompt: \"Read my repository and create a skill to bootstrap new components for my project.\"\n\n<!-- File: core/skills/builtin/skill-creator/references/openai_yaml.md (Tokens: ~492 | Category: anthropic-skill) -->\n# openai.yaml fields (full example + descriptions)\n\n`agents/openai.yaml` is an extended, product-specific config intended for the machine/harness to read, not the agent. Other product-specific config can also live in the `agents/` folder.\n\n## Full example\n\n```yaml\ninterface:\n  display_name: \"Optional user-facing name\"\n  short_description: \"Optional user-facing description\"\n  icon_small: \"./assets/small-400px.png\"\n  icon_large: \"./assets/large-logo.svg\"\n  brand_color: \"#3B82F6\"\n  default_prompt: \"Optional surrounding prompt to use the skill with\"\n\ndependencies:\n  tools:\n    - type: \"mcp\"\n      value: \"github\"\n      description: \"GitHub MCP server\"\n      transport: \"streamable_http\"\n      url: \"https://api.githubcopilot.com/mcp/\"\n```\n\n## Field descriptions and constraints\n\nTop-level constraints:\n\n- Quote all string values.\n- Keep keys unquoted.\n- For `interface.default_prompt`: generate a helpful, short (typically 1 sentence) example starting prompt based on the skill. It must explicitly mention the skill as `$skill-name` (e.g., \"Use $skill-name-here to draft a concise weekly status update.\").\n\n- `interface.display_name`: Human-facing title shown in UI skill lists and chips.\n- `interface.short_description`: Human-facing short UI blurb (25–64 chars) for quick scanning.\n- `interface.icon_small`: Path to a small icon asset (relative to skill dir). Default to `./assets/` and place icons in the skill's `assets/` folder.\n- `interface.icon_large`: Path to a larger logo asset (relative to skill dir). Default to `./assets/` and place icons in the skill's `assets/` folder.\n- `interface.brand_color`: Hex color used for UI accents (e.g., badges).\n- `interface.default_prompt`: Default prompt snippet inserted when invoking the skill.\n- `dependencies.tools[].type`: Dependency category. Only `mcp` is supported for now.\n- `dependencies.tools[].value`: Identifier of the tool or dependency.\n- `dependencies.tools[].description`: Human-readable explanation of the dependency.\n- `dependencies.tools[].transport`: Connection type when `type` is `mcp`.\n- `dependencies.tools[].url`: MCP server URL when `type` is `mcp`.\n\n<!-- File: core/skills/builtin/skill-creator/SKILL.md (Tokens: ~3892 | Category: anthropic-skill) -->\n---\nname: skill-creator\ndescription: Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Codex's capabilities with specialized knowledge, workflows, or tool integrations.\nmetadata:\n  short-description: Create or update a skill\n---\n\n# Skill Creator\n\nThis skill provides guidance for creating effective skills.\n\n## About Skills\n\nSkills are modular, self-contained folders that extend Codex's capabilities by providing\nspecialized knowledge, workflows, and tools. Think of them as \"onboarding guides\" for specific\ndomains or tasks—they transform Codex from a general-purpose agent into a specialized agent\nequipped with procedural knowledge that no model can fully possess.\n\n### What Skills Provide\n\n1. Specialized workflows - Multi-step procedures for specific domains\n2. Tool integrations - Instructions for working with specific file formats or APIs\n3. Domain expertise - Company-specific knowledge, schemas, business logic\n4. Bundled resources - Scripts, references, and assets for complex and repetitive tasks\n\n## Core Principles\n\n### Concise is Key\n\nThe context window is a public good. Skills share the context window with everything else Codex needs: system prompt, conversation history, other Skills' metadata, and the actual user request.\n\n**Default assumption: Codex is already very smart.** Only add context Codex doesn't already have. Challenge each piece of information: \"Does Codex really need this explanation?\" and \"Does this paragraph justify its token cost?\"\n\nPrefer concise examples over verbose explanations.\n\n### Set Appropriate Degrees of Freedom\n\nMatch the level of specificity to the task's fragility and variability:\n\n**High freedom (text-based instructions)**: Use when multiple approaches are valid, decisions depend on context, or heuristics guide the approach.\n\n**Medium freedom (pseudocode or scripts with parameters)**: Use when a preferred pattern exists, some variation is acceptable, or configuration affects behavior.\n\n**Low freedom (specific scripts, few parameters)**: Use when operations are fragile and error-prone, consistency is critical, or a specific sequence must be followed.\n\nThink of Codex as exploring a path: a narrow bridge with cliffs needs specific guardrails (low freedom), while an open field allows many routes (high freedom).\n\n### Anatomy of a Skill\n\nEvery skill consists of a required SKILL.md file and optional bundled resources:\n\n```\nskill-name/\n├── SKILL.md (required)\n│   ├── YAML frontmatter metadata (required)\n│   │   ├── name: (required)\n│   │   └── description: (required)\n│   └── Markdown instructions (required)\n├── agents/ (recommended)\n│   └── openai.yaml - UI metadata for skill lists and chips\n└── Bundled Resources (optional)\n    ├── scripts/          - Executable code (Python/Bash/etc.)\n    ├── references/       - Documentation intended to be loaded into context as needed\n    └── assets/           - Files used in output (templates, icons, fonts, etc.)\n```\n\n#### SKILL.md (required)\n\nEvery SKILL.md consists of:\n\n- **Frontmatter** (YAML): Contains `name` and `description` fields. These are the only fields that Codex reads to determine when the skill gets used, thus it is very important to be clear and comprehensive in describing what the skill is, and when it should be used.\n- **Body** (Markdown): Instructions and guidance for using the skill. Only loaded AFTER the skill triggers (if at all).\n\n#### Agents metadata (recommended)\n\n- UI-facing metadata for skill lists and chips\n- Read references/openai_yaml.md before generating values and follow its descriptions and constraints\n- Create: human-facing `display_name`, `short_description`, and `default_prompt` by reading the skill\n- Generate deterministically by passing the values as `--interface key=value` to `scripts/generate_openai_yaml.py` or `scripts/init_skill.py`\n- On updates: validate `agents/openai.yaml` still matches SKILL.md; regenerate if stale\n- Only include other optional interface fields (icons, brand color) if explicitly provided\n- See references/openai_yaml.md for field definitions and examples\n\n#### Bundled Resources (optional)\n\n##### Scripts (`scripts/`)\n\nExecutable code (Python/Bash/etc.) for tasks that require deterministic reliability or are repeatedly rewritten.\n\n- **When to include**: When the same code is being rewritten repeatedly or deterministic reliability is needed\n- **Example**: `scripts/rotate_pdf.py` for PDF rotation tasks\n- **Benefits**: Token efficient, deterministic, may be executed without loading into context\n- **Note**: Scripts may still need to be read by Codex for patching or environment-specific adjustments\n\n##### References (`references/`)\n\nDocumentation and reference material intended to be loaded as needed into context to inform Codex's process and thinking.\n\n- **When to include**: For documentation that Codex should reference while working\n- **Examples**: `references/finance.md` for financial schemas, `references/mnda.md` for company NDA template, `references/policies.md` for company policies, `references/api_docs.md` for API specifications\n- **Use cases**: Database schemas, API documentation, domain knowledge, company policies, detailed workflow guides\n- **Benefits**: Keeps SKILL.md lean, loaded only when Codex determines it's needed\n- **Best practice**: If files are large (>10k words), include grep search patterns in SKILL.md\n- **Avoid duplication**: Information should live in either SKILL.md or references files, not both. Prefer references files for detailed information unless it's truly core to the skill—this keeps SKILL.md lean while making information discoverable without hogging the context window. Keep only essential procedural instructions and workflow guidance in SKILL.md; move detailed reference material, schemas, and examples to references files.\n\n##### Assets (`assets/`)\n\nFiles not intended to be loaded into context, but rather used within the output Codex produces.\n\n- **When to include**: When the skill needs files that will be used in the final output\n- **Examples**: `assets/logo.png` for brand assets, `assets/slides.pptx` for PowerPoint templates, `assets/frontend-template/` for HTML/React boilerplate, `assets/font.ttf` for typography\n- **Use cases**: Templates, images, icons, boilerplate code, fonts, sample documents that get copied or modified\n- **Benefits**: Separates output resources from documentation, enables Codex to use files without loading them into context\n\n#### What to Not Include in a Skill\n\nA skill should only contain essential files that directly support its functionality. Do NOT create extraneous documentation or auxiliary files, including:\n\n- README.md\n- INSTALLATION_GUIDE.md\n- QUICK_REFERENCE.md\n- CHANGELOG.md\n- etc.\n\nThe skill should only contain the information needed for an AI agent to do the job at hand. It should not contain auxiliary context about the process that went into creating it, setup and testing procedures, user-facing documentation, etc. Creating additional documentation files just adds clutter and confusion.\n\n### Progressive Disclosure Design Principle\n\nSkills use a three-level loading system to manage context efficiently:\n\n1. **Metadata (name + description)** - Always in context (~100 words)\n2. **SKILL.md body** - When skill triggers (<5k words)\n3. **Bundled resources** - As needed by Codex (Unlimited because scripts can be executed without reading into context window)\n\n#### Progressive Disclosure Patterns\n\nKeep SKILL.md body to the essentials and under 500 lines to minimize context bloat. Split content into separate files when approaching this limit. When splitting out content into other files, it is very important to reference them from SKILL.md and describe clearly when to read them, to ensure the reader of the skill knows they exist and when to use them.\n\n**Key principle:** When a skill supports multiple variations, frameworks, or options, keep only the core workflow and selection guidance in SKILL.md. Move variant-specific details (patterns, examples, configuration) into separate reference files.\n\n**Pattern 1: High-level guide with references**\n\n```markdown\n# PDF Processing\n\n## Quick start\n\nExtract text with pdfplumber:\n[code example]\n\n## Advanced features\n\n- **Form filling**: See [FORMS.md](FORMS.md) for complete guide\n- **API reference**: See [REFERENCE.md](REFERENCE.md) for all methods\n- **Examples**: See [EXAMPLES.md](EXAMPLES.md) for common patterns\n```\n\nCodex loads FORMS.md, REFERENCE.md, or EXAMPLES.md only when needed.\n\n**Pattern 2: Domain-specific organization**\n\nFor Skills with multiple domains, organize content by domain to avoid loading irrelevant context:\n\n```\nbigquery-skill/\n├── SKILL.md (overview and navigation)\n└── reference/\n    ├── finance.md (revenue, billing metrics)\n    ├── sales.md (opportunities, pipeline)\n    ├── product.md (API usage, features)\n    └── marketing.md (campaigns, attribution)\n```\n\nWhen a user asks about sales metrics, Codex only reads sales.md.\n\nSimilarly, for skills supporting multiple frameworks or variants, organize by variant:\n\n```\ncloud-deploy/\n├── SKILL.md (workflow + provider selection)\n└── references/\n    ├── aws.md (AWS deployment patterns)\n    ├── gcp.md (GCP deployment patterns)\n    └── azure.md (Azure deployment patterns)\n```\n\nWhen the user chooses AWS, Codex only reads aws.md.\n\n**Pattern 3: Conditional details**\n\nShow basic content, link to advanced content:\n\n```markdown\n# DOCX Processing\n\n## Creating documents\n\nUse docx-js for new documents. See [DOCX-JS.md](DOCX-JS.md).\n\n## Editing documents\n\nFor simple edits, modify the XML directly.\n\n**For tracked changes**: See [REDLINING.md](REDLINING.md)\n**For OOXML details**: See [OOXML.md](OOXML.md)\n```\n\nCodex reads REDLINING.md or OOXML.md only when the user needs those features.\n\n**Important guidelines:**\n\n- **Avoid deeply nested references** - Keep references one level deep from SKILL.md. All reference files should link directly from SKILL.md.\n- **Structure longer reference files** - For files longer than 100 lines, include a table of contents at the top so Codex can see the full scope when previewing.\n\n## Skill Creation Process\n\nSkill creation involves these steps:\n\n1. Understand the skill with concrete examples\n2. Plan reusable skill contents (scripts, references, assets)\n3. Initialize the skill (run init_skill.py)\n4. Edit the skill (implement resources and write SKILL.md)\n5. Validate the skill (run quick_validate.py)\n6. Iterate based on real usage\n\nFollow these steps in order, skipping only if there is a clear reason why they are not applicable.\n\n### Skill Naming\n\n- Use lowercase letters, digits, and hyphens only; normalize user-provided titles to hyphen-case (e.g., \"Plan Mode\" -> `plan-mode`).\n- When generating names, generate a name under 64 characters (letters, digits, hyphens).\n- Prefer short, verb-led phrases that describe the action.\n- Namespace by tool when it improves clarity or triggering (e.g., `gh-address-comments`, `linear-address-issue`).\n- Name the skill folder exactly after the skill name.\n\n### Step 1: Understanding the Skill with Concrete Examples\n\nSkip this step only when the skill's usage patterns are already clearly understood. It remains valuable even when working with an existing skill.\n\nTo create an effective skill, clearly understand concrete examples of how the skill will be used. This understanding can come from either direct user examples or generated examples that are validated with user feedback.\n\nFor example, when building an image-editor skill, relevant questions include:\n\n- \"What functionality should the image-editor skill support? Editing, rotating, anything else?\"\n- \"Can you give some examples of how this skill would be used?\"\n- \"I can imagine users asking for things like 'Remove the red-eye from this image' or 'Rotate this image'. Are there other ways you imagine this skill being used?\"\n- \"What would a user say that should trigger this skill?\"\n\nTo avoid overwhelming users, avoid asking too many questions in a single message. Start with the most important questions and follow up as needed for better effectiveness.\n\nConclude this step when there is a clear sense of the functionality the skill should support.\n\n### Step 2: Planning the Reusable Skill Contents\n\nTo turn concrete examples into an effective skill, analyze each example by:\n\n1. Considering how to execute on the example from scratch\n2. Identifying what scripts, references, and assets would be helpful when executing these workflows repeatedly\n\nExample: When building a `pdf-editor` skill to handle queries like \"Help me rotate this PDF,\" the analysis shows:\n\n1. Rotating a PDF requires re-writing the same code each time\n2. A `scripts/rotate_pdf.py` script would be helpful to store in the skill\n\nExample: When designing a `frontend-webapp-builder` skill for queries like \"Build me a todo app\" or \"Build me a dashboard to track my steps,\" the analysis shows:\n\n1. Writing a frontend webapp requires the same boilerplate HTML/React each time\n2. An `assets/hello-world/` template containing the boilerplate HTML/React project files would be helpful to store in the skill\n\nExample: When building a `big-query` skill to handle queries like \"How many users have logged in today?\" the analysis shows:\n\n1. Querying BigQuery requires re-discovering the table schemas and relationships each time\n2. A `references/schema.md` file documenting the table schemas would be helpful to store in the skill\n\nTo establish the skill's contents, analyze each concrete example to create a list of the reusable resources to include: scripts, references, and assets.\n\n### Step 3: Initializing the Skill\n\nAt this point, it is time to actually create the skill.\n\nSkip this step only if the skill being developed already exists. In this case, continue to the next step.\n\nWhen creating a new skill from scratch, always run the `init_skill.py` script. The script conveniently generates a new template skill directory that automatically includes everything a skill requires, making the skill creation process much more efficient and reliable.\n\nUsage:\n\n```bash\nscripts/init_skill.py <skill-name> --path <output-directory> [--resources scripts,references,assets] [--examples]\n```\n\nExamples:\n\n```bash\nscripts/init_skill.py my-skill --path skills/public\nscripts/init_skill.py my-skill --path skills/public --resources scripts,references\nscripts/init_skill.py my-skill --path skills/public --resources scripts --examples\n```\n\nThe script:\n\n- Creates the skill directory at the specified path\n- Generates a SKILL.md template with proper frontmatter and TODO placeholders\n- Creates `agents/openai.yaml` using agent-generated `display_name`, `short_description`, and `default_prompt` passed via `--interface key=value`\n- Optionally creates resource directories based on `--resources`\n- Optionally adds example files when `--examples` is set\n\nAfter initialization, customize the SKILL.md and add resources as needed. If you used `--examples`, replace or delete placeholder files.\n\nGenerate `display_name`, `short_description`, and `default_prompt` by reading the skill, then pass them as `--interface key=value` to `init_skill.py` or regenerate with:\n\n```bash\nscripts/generate_openai_yaml.py <path/to/skill-folder> --interface key=value\n```\n\nOnly include other optional interface fields when the user explicitly provides them. For full field descriptions and examples, see references/openai_yaml.md.\n\n### Step 4: Edit the Skill\n\nWhen editing the (newly-generated or existing) skill, remember that the skill is being created for another instance of Codex to use. Include information that would be beneficial and non-obvious to Codex. Consider what procedural knowledge, domain-specific details, or reusable assets would help another Codex instance execute these tasks more effectively.\n\n#### Start with Reusable Skill Contents\n\nTo begin implementation, start with the reusable resources identified above: `scripts/`, `references/`, and `assets/` files. Note that this step may require user input. For example, when implementing a `brand-guidelines` skill, the user may need to provide brand assets or templates to store in `assets/`, or documentation to store in `references/`.\n\nAdded scripts must be tested by actually running them to ensure there are no bugs and that the output matches what is expected. If there are many similar scripts, only a representative sample needs to be tested to ensure confidence that they all work while balancing time to completion.\n\nIf you used `--examples`, delete any placeholder files that are not needed for the skill. Only create resource directories that are actually required.\n\n#### Update SKILL.md\n\n**Writing Guidelines:** Always use imperative/infinitive form.\n\n##### Frontmatter\n\nWrite the YAML frontmatter with `name` and `description`:\n\n- `name`: The skill name\n- `description`: This is the primary triggering mechanism for your skill, and helps Codex understand when to use the skill.\n  - Include both what the Skill does and specific triggers/contexts for when to use it.\n  - Include all \"when to use\" information here - Not in the body. The body is only loaded after triggering, so \"When to Use This Skill\" sections in the body are not helpful to Codex.\n  - Example description for a `docx` skill: \"Comprehensive document creation, editing, and analysis with support for tracked changes, comments, formatting preservation, and text extraction. Use when Codex needs to work with professional documents (.docx files) for: (1) Creating new documents, (2) Modifying or editing content, (3) Working with tracked changes, (4) Adding comments, or any other document tasks\"\n\nDo not include any other fields in YAML frontmatter.\n\n##### Body\n\nWrite instructions for using the skill and its bundled resources.\n\n### Step 5: Validate the Skill\n\nOnce development of the skill is complete, validate the skill folder to catch basic issues early:\n\n```bash\nscripts/quick_validate.py <path/to/skill-folder>\n```\n\nThe validation script checks YAML frontmatter format, required fields, and naming rules. If validation fails, fix the reported issues and run the command again.\n\n### Step 6: Iterate\n\nAfter testing the skill, users may request improvements. Often this happens right after using the skill, with fresh context of how the skill performed.\n\n**Iteration workflow:**\n\n1. Use the skill on real tasks\n2. Notice struggles or inefficiencies\n3. Identify how SKILL.md or bundled resources should be updated\n4. Implement changes and test again\n\n<!-- ... +2 more modular skills available via /api/skills/HKUDS/DeepCode?path={path} -->\n</yakaai_skills>"}