
Openai Security Best Practices
- 71 installs
- 475 repo stars
- Updated July 14, 2026
- trailofbits/skills-curated
Helps with security tasks during AI-assisted development.
About
openai-security-best-practices is a Claude Code skill for security. It helps solo builders move faster with AI-assisted coding.
- openai-security-best-practices
- Security
- AI-coding skill
Openai Security Best Practices by the numbers
- 71 all-time installs (skills.sh)
- +6 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #1,170 of 2,203 Security skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/trailofbits/skills-curated --skill openai-security-best-practicesAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 71 |
|---|---|
| repo stars | ★ 475 |
| Last updated | July 14, 2026 |
| Repository | trailofbits/skills-curated ↗ |
What it does
Helps with security tasks during AI-assisted development.
Files
Security Best Practices
Overview
This 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.
This 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.
Workflow
The 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.
Then 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.
If 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!
If 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.
If 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.
From there it can operate in a few ways.
1. 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.
2. 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.
3. 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.
Workflow Decision Tree
- If the language/framework is unclear, inspect the repo to determine it and list your evidence.
- If matching guidance exists in
references/, load only the relevant files and follow their instructions. - 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)
Overrides
While 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.
Report Format
When 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.
The report should have a short executive summary at the top.
The 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.
For critical findings include a one sentence impact statement.
Once 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.
Important: When referencing code in the report, make sure to find and include line numbers for the code you are referencing.
After you write the report file, summarize the findings to the user.
Also tell the user where the final report was written to
Fixes
If you produced a report, let the user read the report and ask to begin performing fixes.
If you passively found a critical finding, notify the user and ask if they would like you to fix this finding.
When 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.
Always 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.
Always 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.
Always 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.
General Security Advice
Below is a few bits of secure coding advice that applies to almost any language or framework.
Avoid Using Incrementing IDs for Public IDs of Resources
When 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.
A note on TLS
While 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 the agent.
When to Use
<!-- TODO: review -->
When NOT to Use
<!-- TODO: review -->
Go (Golang) Security Spec (Go 1.25.x, Standard Library, net/http)
This document is designed as a security spec that supports: 1) Secure-by-default code generation for new Go code. 2) Security review / vulnerability hunting in existing Go code (passive “notice issues while working” and active “scan the repo and report findings”).
It 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).
--------------------------------------------------------------------
0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)
- MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session cookies, JWTs, database URLs with credentials, signing keys, client secrets).
- MUST NOT “fix” security by disabling protections (e.g.,
InsecureSkipVerify,GOSUMDB=offfor public modules, wildcard CORS + credentials, removing auth checks, disabling CSRF defenses on cookie-auth apps). - MUST provide evidence-based findings during audits: cite file paths, code snippets, build/deploy configs, and concrete values that justify the claim.
- 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.”
- MUST keep fixes minimal, correct, and production-safe; avoid introducing breaking changes without warning (especially around auth/session flows, and proxies).
--------------------------------------------------------------------
1) Operating modes
1.1 Generation mode (default)
When asked to write new Go code or modify existing code:
- MUST follow every MUST requirement in this spec.
- SHOULD follow every SHOULD requirement unless the user explicitly says otherwise.
- MUST prefer safe-by-default APIs and proven libraries over custom security code.
- MUST avoid introducing new risky sinks (shell execution, dynamic template execution, serving user files as HTML, unsafe redirects, weak crypto, unbounded parsing, etc.).
1.2 Passive review mode (always on while editing)
While working anywhere in a Go repo (even if the user did not ask for a security scan):
- MUST “notice” violations of this spec in touched/nearby code.
- SHOULD mention issues as they come up, with a brief explanation + safe fix.
1.3 Active audit mode (explicit scan request)
When the user asks to “scan”, “audit”, or “hunt for vulns”:
- MUST systematically search the codebase for violations of this spec.
- MUST output findings in a structured format (see §2.3).
Recommended audit order: 1) Build/deploy entrypoints: main.go, cmd/*, Dockerfiles, Kubernetes manifests, systemd units, CI workflows. 2) Go toolchain & dependency policy: Go version, modules, go.mod/go.sum, proxy/sumdb settings, govulncheck usage. 3) Secret management and config loading (env, files, secret stores) + logging patterns. 4) HTTP server configuration (timeouts, body limits, proxy trust, security headers). 5) AuthN/AuthZ boundaries, session/cookie settings, token validation. 6) CSRF protections for cookie-authenticated state-changing endpoints. 7) Template usage and output encoding (XSS), and any “render template from string” behavior (SSTI). 8) File handling (uploads/downloads/path traversal/temp files), static file serving. 9) Injection sinks: SQL, OS command execution, SSRF/outbound fetch, open redirects. 10) Concurrency/resource exhaustion (unbounded goroutines/queues, missing timeouts/contexts). 11) Use of unsafe / cgo / reflect in security-sensitive paths. 12) Debug/diagnostic endpoints (pprof/expvar/metrics) exposure. 13) Cryptography usage (randomness, password hashing).
--------------------------------------------------------------------
2) Definitions and review guidance
2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)
Examples include:
*http.Requestfields:r.URL.Path,r.URL.RawQuery,r.Form,r.PostForm, headers, cookies,r.Body- Path parameters from routers (including values extracted from URL paths)
- JSON/XML/YAML bodies, multipart form parts, uploaded files
- Any data from external systems (webhooks, third-party APIs, message queues)
- Any persisted user content (DB rows) that originated from users
- Configuration values that might be attacker-influenced in some deployments (headers set by upstream proxies, environment variables in multi-tenant systems)
2.2 State-changing request
A 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.
2.3 Required audit finding format
For each issue found, output:
- Rule ID:
- Severity: Critical / High / Medium / Low
- Location: file path + function/handler name + line(s)
- Evidence: the exact code/config snippet
- Impact: what could go wrong, who can exploit it
- Fix: safe change (prefer minimal diff)
- Mitigation: defense-in-depth if immediate fix is hard
- False positive notes: what to verify if uncertain (edge configs, proxy behavior, auth assumptions)
--------------------------------------------------------------------
3) Secure baseline: minimum production configuration (MUST in production)
This is the smallest “production baseline” that prevents common Go misconfigurations.
3.1 Toolchain, patching, and dependency hygiene (MUST)
- MUST run a supported Go major version and keep to the latest patch releases.
- MUST treat Go standard library patch releases as security-relevant (many security fixes land in stdlib components like
net/http,crypto/*, parsing packages). - MUST use Go modules with committed
go.modandgo.sum. - MUST NOT disable module authenticity mechanisms for public modules (checksum DB) unless you have a controlled, documented replacement.
- MUST run
govulncheck(source scan and/or binary scan) in CI and address findings.
3.2 HTTP server baseline (MUST for network-facing services)
If the program serves HTTP (directly or via a framework built on net/http):
- MUST configure an
http.Serverwith explicit timeouts and header limits. - MUST set request body size limits (global and per-route as needed).
- MUST avoid exposing diagnostic endpoints (pprof/expvar) publicly.
- SHOULD set a consistent set of security headers (or verify they are set at the edge).
- MUST set cookie security attributes for any cookies you issue.
- SHOULD implement rate limiting and abuse controls for auth and expensive endpoints.
Illustrative baseline skeleton (adjust to your project):
- Create a dedicated mux (avoid implicit global defaults unless intentionally managed).
- Wrap handlers with: panic-safe error handling, request ID, logging, auth, and limits.
--------------------------------------------------------------------
4) Rules (generation + audit)
Each rule contains: required practice, insecure patterns, detection hints, and remediation.
GO-DEPLOY-001: Keep the Go toolchain and standard library updated (security releases)
Severity: Medium
NOTE: 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.
Required:
- MUST run a supported Go major release and apply patch releases promptly.
- SHOULD treat patch releases as security-relevant, even if your application code didn’t change.
Insecure patterns:
- Production builds pinned to old Go versions without a patching process.
- Docker images like
golang:1.xxor custom base images that are not updated regularly. - CI pipelines that intentionally suppress Go updates.
Detection hints:
- Inspect CI (
.github/workflows,gitlab-ci.yml, etc.) forgo-version:or toolchain setup. - Inspect Dockerfiles for
FROM golang:tags. - Inspect
go.modgodirective and any toolchain pinning.
Fix:
- Upgrade to the latest patch of a supported Go version.
- Add an automated check (CI) that fails when Go is below an approved minimum.
Notes:
- Go publishes regular minor releases that frequently include security fixes across standard library packages.
---
GO-SUPPLY-001: Go module authenticity MUST NOT be disabled for public dependencies
Severity: High
Required:
- MUST keep module checksum verification enabled for public modules.
- SHOULD commit
go.sumand treat changes as security-sensitive. - MUST NOT use insecure module fetching settings for public modules.
- MAY configure private module behavior using
GOPRIVATE/GONOSUMDBfor private repos, but must do so narrowly and intentionally.
Insecure patterns:
GOSUMDB=offin CI or production build environments for public modules.GONOSUMDB=*or overly broad patterns that effectively disable verification.GOINSECURE=*or broadGOINSECUREpatterns for public modules.GOPROXY=directeverywhere without a clear policy.
Detection hints:
- Search build configs for
GOSUMDB,GONOSUMDB,GOINSECURE,GOPROXY,GOPRIVATE. - Look for documentation/scripts that recommend disabling checksum DB “to make builds work”.
Fix:
- Restore defaults for public module verification.
- For private modules:
- Set
GOPRIVATE=your.private.domain/* - Configure an internal proxy or direct fetching, and restrict
GONOSUMDBto private patterns only.
Notes:
- Disabling checksum verification removes an important integrity layer against targeted or compromised upstream delivery.
---
GO-CONFIG-001: Secrets must be externalized and never logged or committed
Severity: High (Critical if credentials are committed)
Required:
- MUST load secrets from environment variables, secret managers, or secure config files with restricted permissions.
- MUST NOT hard-code secrets in Go source, test fixtures that may reach production, or build args.
- MUST NOT log secrets or full credential-bearing connection strings.
- SHOULD fail closed in production if required secrets are missing.
Insecure patterns:
- String constants containing tokens/keys/passwords.
.envfiles or config files with secrets committed to repo.- Logging
os.Environ(), dumping full configs, or printing DSNs.
Detection hints:
- Search for suspicious literals (
API_KEY,SECRET,PASSWORD,Authorization:). - Inspect config loaders and logging statements.
- Inspect CI logs or debug print paths.
Fix:
- Move secrets to a secret store / environment variables.
- Redact sensitive fields in logs.
- Add secret scanning to CI and pre-commit.
---
GO-HTTP-001: HTTP servers MUST set timeouts and MaxHeaderBytes
Severity: High (DoS risk)
Required:
- MUST set:
ReadHeaderTimeout, and SHOULD setReadTimeout,WriteTimeout,IdleTimeoutas appropriate for the service. - MUST set
MaxHeaderBytesto a justified limit for your application. - MUST NOT rely on default zero-values for timeouts in production for internet-facing servers.
Insecure patterns:
http.ListenAndServe(":8080", handler)with a defaulthttp.Server(no explicit timeouts).&http.Server{}with timeouts left at zero.- Missing
MaxHeaderBytes.
Detection hints:
- Search for
http.ListenAndServe(,ListenAndServeTLS(,Server{and inspect configured fields. - Check for reverse proxies; even with a proxy, app-level timeouts still matter.
Fix:
- Use
http.Server{ReadHeaderTimeout: ..., ReadTimeout: ..., WriteTimeout: ..., IdleTimeout: ..., MaxHeaderBytes: ...}. - Calibrate timeouts per endpoint type (streaming vs JSON APIs).
Notes:
- Net/http documents that these timeouts exist and that zero/negative values mean “no timeout”; production services should choose explicit values.
---
GO-HTTP-002: Request body and multipart parsing MUST be size-bounded
Severity: Medium (DoS risk; can be High for upload-heavy apps)
Required:
- MUST enforce a global maximum request body size for endpoints that accept bodies.
- MUST enforce strict multipart upload limits and avoid unbounded form parsing.
- SHOULD enforce per-route limits when some endpoints legitimately need larger bodies.
- SHOULD set upstream (proxy) limits as defense-in-depth.
Insecure patterns:
- Reading
r.Bodywithio.ReadAll(r.Body)without a size cap. - Calling
r.ParseMultipartForm(...)with overly large limits (or forgetting size controls). - Accepting file uploads with no limits on file size, number of parts, or total body size.
Detection hints:
- Search for
io.ReadAll(r.Body),json.NewDecoder(r.Body),ParseMultipartForm,FormFile,multipart. - Look for missing
http.MaxBytesReaderor equivalent per-handler limiting. - Look for “upload” endpoints and check limits.
Fix:
- Wrap request bodies with
http.MaxBytesReader(w, r.Body, maxBytes)before parsing. - For multipart, set conservative limits and validate file sizes/part counts explicitly.
- Set proxy limits (e.g., at ingress) in addition to app limits.
Notes:
- There are known vulnerability classes and advisories related to excessive resource consumption in multipart/form parsing; treat unbounded parsing as a security issue.
---
GO-DEPLOY-002: Diagnostic endpoints (pprof/expvar/metrics) MUST NOT be publicly exposed
Severity: High
NOTE: 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.
Required:
- MUST NOT expose
net/http/pprofhandlers on a public internet-facing listener without strong access controls. - SHOULD run diagnostics on a separate, internal-only listener (loopback/VPC-only) and require auth.
- MUST review what diagnostic endpoints reveal (stack traces, memory, command lines, environment, internal URLs).
Insecure patterns:
- Side-effect import
import _ "net/http/pprof"in a server binary with a public mux. /debug/pprof/*reachable without auth./debug/vars(expvar) reachable without auth.
Detection hints:
- Search for
net/http/pprofimports (including blank imports). - Search for route prefixes
/debug/pprof,/debug/vars. - Check whether
http.DefaultServeMuxis used and whether any debug handlers register globally.
Fix:
- Remove diagnostics from production builds, or bind them to an internal-only listener.
- Add strong authentication/authorization (and ideally network-level restrictions).
Notes:
- pprof is typically imported for its side effect of registering HTTP handlers under
/debug/pprof/.
---
GO-HTTP-003: Reverse proxy and forwarded header trust MUST be explicit
Severity: High (auth, URL generation, logging/auditing correctness)
Required:
- If behind a reverse proxy, MUST define which proxy is trusted and how client IP/scheme/host are derived.
- MUST NOT trust
X-Forwarded-For,X-Forwarded-Proto,Forwarded, or similar headers from the open internet. - MUST ensure “secure cookie” logic, redirects, and absolute URL generation do not rely on spoofable headers.
Insecure patterns:
- Using
r.Header.Get("X-Forwarded-For")as the client IP without validating the proxy boundary. - Deriving “is HTTPS” from
X-Forwarded-Protowithout confirming it came from a trusted proxy. - Using forwarded
Hostvalues for password reset links without allowlisting.
Detection hints:
- Search for
X-Forwarded-For,X-Forwarded-Proto,Forwarded,Real-IP, and any custom “client IP” helpers. - Inspect ingress/proxy configs; if not visible, mark as “verify at edge”.
Fix:
- Enforce proxy trust at the edge and in app:
- Accept forwarded headers only from known proxy IP ranges.
- Prefer platform-provided mechanisms where available.
- If generating external links, use a configured allowlisted canonical origin (not the request’s Host header).
---
GO-HTTP-004: Security headers SHOULD be set (in app or at the edge)
Severity: Medium
Required (typical web app serving browsers):
- SHOULD set:
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.X-Content-Type-Options: nosniff- Clickjacking protection (
X-Frame-Optionsand/or CSPframe-ancestors) Referrer-PolicyandPermissions-Policywhere appropriate- MUST ensure cookies have secure attributes (see GO-HTTP-005).
NOTE:
- These headers may be set via reverse proxy/CDN; if not visible in app code, report as “verify at edge”.
Insecure patterns:
- No security headers anywhere (app or edge) for a browser-facing app.
- CSP missing for apps rendering untrusted content.
Detection hints:
- Search for middleware setting headers:
w.Header().Set("Content-Security-Policy", ...), etc. - Search for reverse proxy config that sets headers.
Fix:
- Add centralized header middleware in Go, or configure at the edge.
- Keep CSP realistic; avoid
unsafe-inlinewhere possible.
---
GO-HTTP-005: Cookies MUST use secure attributes in production
Severity: Medium
Required (production, HTTPS):
- MUST set
Secureon cookies that carry auth/session state. IMPORTANT NOTE: Only setSecurein production environment when TLS is configured. When running in a local dev environment over HTTP, do not setSecureproperty on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property likeSESSION_COOKIE_SECUREwhich can be used to disableSecurecookies when testing over HTTP. - MUST set
HttpOnlyon auth/session cookies. - SHOULD set
SameSite=Laxby default (orStrictif compatible), and only useNonewhen necessary (and only withSecure). - SHOULD set bounded lifetimes (
Max-Age/Expires) appropriate to the app.
Insecure patterns:
- Setting auth/session cookies without
Securein HTTPS deployments. - Cookies without
HttpOnlyfor session identifiers. SameSite=Nonefor cookie-authenticated apps without a strong CSRF strategy.
Detection hints:
- Search for
http.SetCookie,&http.Cookie{,Set-Cookie. - Inspect cookie flags in auth/session code.
Fix:
- Set the correct fields on
http.Cookieand centralize cookie creation.
Notes:
- SameSite is defense-in-depth and does not replace CSRF protections for cookie-auth apps.
---
GO-HTTP-006: Cookie-authenticated state-changing endpoints MUST be CSRF-protected
Severity: High
- 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.
Required:
- MUST protect all state-changing endpoints (POST/PUT/PATCH/DELETE) that rely on cookies for authentication.
- SHOULD use a well-tested CSRF library/middleware rather than rolling your own.
- MAY use additional defenses (Origin/Referer checks, Fetch Metadata, SameSite cookies), but tokens remain the primary defense for cookie-authenticated apps.
If tokens are impractical, or for small applications:
- 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.
Insecure patterns:
- Cookie-authenticated JSON endpoints that mutate state with no CSRF checks.
- Using GET for state-changing actions.
Detection hints:
- Enumerate all non-GET routes and identify auth mechanism.
- Look for CSRF middleware usage; if absent, treat as suspicious in browser-facing apps.
Fix:
- Add CSRF middleware and ensure it covers all state-changing routes.
- If the service is an API intended for non-browser clients, avoid cookie auth; use Authorization headers.
---
GO-HTTP-007: CORS must be explicit and least-privilege
Severity: Medium (High if misconfigured with credentials)
Required:
- If CORS is not needed, MUST keep it disabled.
- If CORS is needed:
- MUST allowlist trusted origins (do not reflect arbitrary origins)
- MUST be careful with credentialed requests; do not combine broad origins with cookies
- SHOULD restrict allowed methods/headers
Insecure patterns:
Access-Control-Allow-Origin: *paired with cookies (Access-Control-Allow-Credentials: true).- Reflecting
Originwithout validation.
Detection hints:
- Search for
Access-Control-Allow-header setting. - Search for CORS middleware configuration.
Fix:
- Implement strict origin allowlists and minimal methods/headers.
- Ensure cookie-auth endpoints are not exposed cross-origin unless required.
---
GO-XSS-001: Use html/template and avoid bypassing auto-escaping with untrusted data
Severity: High
Required:
- MUST use
html/templatefor HTML rendering (nottext/template). - MUST NOT convert untrusted data into “trusted” template types (
template.HTML,template.JS,template.URL, etc.). - SHOULD keep templates static and controlled by developers; treat dynamic templates as high risk.
- MUST NOT serve user-uploaded HTML/JS as active content unless explicitly intended and safely sandboxed.
Insecure patterns:
text/templateused to generate HTML.- Using
template.HTML(userInput)or similar typed wrappers. - Directly writing unescaped user content into HTML responses.
Detection hints:
- Search for
text/template,template.New(...).Parse(...), and typed wrappers liketemplate.HTML(. - Inspect handlers that return HTML with string concatenation.
Fix:
- Use
html/templateand pass untrusted data as data, not markup. - If you must allow limited HTML, use a vetted HTML sanitizer and still be careful with attributes/URLs.
---
GO-SSTI-001: Never parse/execute templates from untrusted input (SSTI)
Severity: Critical
Required:
- MUST NOT call
template.Parse/template.ParseFiles/template.New(...).Parse(...)on template text influenced by untrusted input. - MUST treat “user-defined templates” as a special high-risk design:
- MUST use heavy sandboxing and strict allowlists
- MUST isolate execution (process/container boundary) if truly required
Insecure patterns:
tmpl := template.Must(template.New("x").Parse(r.FormValue("tmpl")))- Reading templates from uploads / DB entries and executing them in the same trust domain as server code.
Detection hints:
- Search for
.Parse(and trace the origin of the template string. - Look for “custom email templates”, “user theming templates”, etc.
Fix:
- Replace with safe substitution mechanisms (no code execution).
- If templates must be user-controlled, isolate and sandbox aggressively.
---
GO-PATH-001: Prevent path traversal and unsafe file serving
Severity: High
Required:
- MUST NOT pass user-controlled paths to
os.Open,os.ReadFile,http.ServeFile, orhttp.FileServerwithout strict validation and base-dir enforcement. - MUST treat
.., absolute paths, and OS-specific path tricks as hostile input. - SHOULD store user uploads outside any static web root; serve through controlled handlers.
- MUST avoid directory listing for sensitive file trees.
Insecure patterns:
http.ServeFile(w, r, r.URL.Query().Get("path"))os.Open(filepath.Join(baseDir, userPath))without checking that the result stays underbaseDirhttp.FileServer(http.Dir("."))serving the project root or user-writable directories
Detection hints:
- Search for
ServeFile(,FileServer(,http.Dir(,os.Open(,ReadFile(,filepath.Join(. - Trace whether path components come from request/DB.
Fix:
- Use an allowlist of file identifiers (e.g., database IDs) mapped to server-side paths.
- Enforce base directory containment after cleaning and joining.
- Serve active formats as downloads (
Content-Disposition: attachment) unless explicitly intended.
---
GO-UPLOAD-001: File uploads must be validated, stored safely, and served safely
Severity: High
Required:
- MUST enforce upload size limits (app + edge).
- MUST validate file type using allowlists and content checks (not only extensions).
- MUST store uploads outside executable/static roots when possible.
- SHOULD generate server-side filenames (random IDs) and avoid trusting original names.
- MUST serve potentially active formats safely (download attachment) unless explicitly intended.
Insecure patterns:
- Accepting arbitrary file types and serving them back inline.
- Using user-supplied filename as storage path.
- Missing size/type validation.
Detection hints:
- Search for
multipart,FormFile,ParseMultipartForm,io.Copyto disk. - Check where files are stored and how they are served.
Fix:
- Implement allowlist validation + safe storage + safe serving.
- Add scanning/quarantine workflows where applicable.
---
GO-INJECT-001: Prevent SQL injection (parameterized queries / ORM)
Severity: High
Required:
- MUST use parameterized queries or an ORM that parameterizes under the hood.
- MUST NOT build SQL by string concatenation /
fmt.Sprintf/ string interpolation with untrusted input.
Insecure patterns:
fmt.Sprintf("SELECT ... WHERE id=%s", r.URL.Query().Get("id"))query := "UPDATE users SET role='" + role + "' WHERE id=" + id
Detection hints:
- Grep for
SELECT,INSERT,UPDATE,DELETEand check how query strings are built. - Trace untrusted data into
db.Query,db.Exec,QueryRow, etc.
Fix:
- Replace with placeholders (
?,$1, etc.) and pass parameters separately. - Validate and type-check IDs before use.
---
GO-INJECT-002: Prevent OS command injection; avoid shelling out with untrusted input
Severity: Critical to High (depends on exposure)
Required:
- MUST avoid executing external commands with attacker-controlled strings.
- If subprocess is necessary:
- MUST use
exec.CommandContextwith an argument list (notsh -c). - MUST NOT pass untrusted input to a shell (
bash -c,sh -c, PowerShell). - SHOULD use strict allowlists for any variable component (subcommand, flags, filenames).
- MUST assume CLI tools may interpret attacker-controlled args as flags or special values.
Insecure patterns:
exec.Command("sh", "-c", userString)exec.Command("bash", "-c", fmt.Sprintf("tool %s", user))- Calling the shell to get glob expansion for user-supplied globs.
Detection hints:
- Search for
os/exec,exec.Command(,CommandContext(,"sh","bash","-c". - Trace untrusted input into command name/args.
Fix:
- Use library APIs instead of subprocesses.
- Hardcode command and allowlist/validate args.
- If a shell is unavoidable, escape robustly and treat as high risk (prefer avoiding).
Notes:
- The Go
os/execpackage intentionally does invoke a shell; introducingsh -creintroduces shell injection hazards.
---
GO-SSRF-001: Prevent SSRF in outbound HTTP requests
Severity: Medium (High in cloud/LAN environments)
- 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.
Required:
- MUST treat outbound requests to user-provided URLs as high risk.
- SHOULD allowlist hosts/domains for any user-influenced URL fetch.
- SHOULD block access to localhost/private IP ranges/link-local addresses and cloud metadata endpoints.
- MUST restrict schemes to
http/https(nofile:,gopher:, etc.). - MUST set client timeouts and restrict redirects.
Insecure patterns:
http.Get(r.URL.Query().Get("url"))- “URL preview” / “webhook test” endpoints that fetch arbitrary URLs.
Detection hints:
- Search for
http.Get,client.Do, and URL values derived from requests/DB. - Identify features that fetch remote resources.
Fix:
- Parse URLs strictly; enforce scheme and allowlisted hostnames.
- Resolve DNS and enforce IP-range restrictions (with care for DNS rebinding).
- Set timeouts, disable redirects unless needed, and cap response sizes.
---
GO-HTTPCLIENT-001: Outbound HTTP clients MUST set timeouts and close bodies
Severity: High (DoS and resource exhaustion)
Required:
- MUST set an overall timeout on
http.Clientusage (or equivalent per-request deadlines via context + transport timeouts). - MUST ensure
resp.Body.Close()is called for all successful requests (typicallydefer resp.Body.Close()immediately after error check). - SHOULD limit response body reads (do not
io.ReadAllunbounded responses). - SHOULD restrict redirects for security-sensitive fetches (SSRF, auth flows).
Insecure patterns:
- Using
http.DefaultClient/http.Getfor user-influenced destinations with no timeout policy. - Missing
defer resp.Body.Close()leading to resource leaks. io.ReadAll(resp.Body)with no limit.
Detection hints:
- Search for
http.Get(,http.Post(,client := &http.Client{}withoutTimeout,client.Do(and missing closes. - Search for
io.ReadAll(resp.Body).
Fix:
- Use a configured client with timeouts.
- Always close response bodies.
- Use bounded readers (
io.LimitReader) for large/untrusted responses.
Notes:
- The net/http package exposes
DefaultClientas a zero-valuedhttp.Client, which can easily lead to “no timeout” behavior unless configured.
---
GO-REDIRECT-001: Prevent open redirects
Severity: Medium (can be High with auth flows)
Required:
- MUST validate redirect targets derived from untrusted input (
next,redirect,return_to). - SHOULD prefer only same-site relative paths.
- SHOULD fall back to a safe default on validation failure.
Insecure patterns:
http.Redirect(w, r, r.URL.Query().Get("next"), http.StatusFound)with no validation.
Detection hints:
- Search for
http.Redirect(and check origin of the location.
Fix:
- Allowlist internal paths or known domains.
- Reject absolute URLs unless explicitly needed and allowlisted.
---
GO-CRYPTO-001: Cryptographic randomness MUST come from crypto/rand
Severity: High (Critical if used for auth/session tokens or keys)
Required:
- MUST use
crypto/randfor: - session IDs, password reset tokens, API keys, CSRF tokens, nonces
- encryption keys, signing keys, salts when required
- MUST NOT use
math/randfor any security-sensitive value. - SHOULD use built-in helpers that produce appropriately strong tokens when available.
Insecure patterns:
math/rand.Seed(time.Now().UnixNano())followed by token generation for auth or sessions.- Using UUIDv4-like constructs built from
math/rand.
Detection hints:
- Search for
math/rand,rand.Seed,rand.Intnin code that touches auth/session/token flows. - Search for custom token generators.
Fix:
- Switch to
crypto/rand(rand.Reader,rand.Read, or secure token helpers). - Ensure sufficient entropy and use URL-safe encoding.
Notes:
- The crypto/rand package provides secure randomness APIs and token generation helpers.
---
GO-AUTH-001: Password storage MUST use adaptive hashing (bcrypt/argon2id) and safe comparisons
Severity: High
Required:
- MUST hash passwords using an adaptive password hashing function (bcrypt or argon2id).
- MUST NOT store plaintext passwords or reversible encryption of passwords.
- MUST compare secrets in constant time when relevant (tokens, MACs, API keys) to reduce timing leaks.
- SHOULD ensure password policies do not exceed algorithm constraints (e.g., bcrypt has input length limits; handle long passphrases appropriately).
Insecure patterns:
sha256(password)stored as password hash.- Plaintext password storage.
- Comparing secrets with
==in timing-sensitive contexts.
Detection hints:
- Search for
sha1,sha256,md5used on passwords. - Search for
bcrypt/argon2usage; if absent, suspect. - Search for
==comparisons on tokens/API keys.
Fix:
- Use
bcrypt.GenerateFromPassword/CompareHashAndPasswordor argon2id with recommended parameters. - Use constant-time compare helpers when comparing MACs/tokens.
Notes:
- Go provides bcrypt in
golang.org/x/crypto/bcrypt, and constant-time comparisons incrypto/subtle.
---
GO-CONC-001: Data races and concurrency hazards MUST be treated as security-relevant
Severity: Medium to High (depends on what races affect)
Required:
- MUST run tests with the race detector (
go test -race) in CI for security-sensitive services. - MUST fix detected races; do not suppress without deep justification.
- SHOULD treat shared mutable state in handlers as high risk; enforce synchronization or avoid shared mutability.
Insecure patterns:
- Global maps/slices mutated from multiple goroutines without a mutex.
- Caches or auth/session state stored in globals without concurrency protection.
- Racy access to authorization state (can lead to bypasses or inconsistent enforcement).
Detection hints:
- Search for
var someMap = map[...]...used in handlers. - Look for missing
sync.Mutex,sync.Map, channels, or other synchronization. - Ensure CI includes
-raceand that it runs relevant tests.
Fix:
- Add proper synchronization or redesign to avoid shared mutable state.
- Add race tests and run them continuously.
Notes:
- The Go race detector only finds races that occur in executed code paths; improve test coverage and run realistic workloads with
-racewhere feasible.
---
GO-UNSAFE-001: Use of unsafe/cgo MUST be minimized and audited like memory-unsafe code
Severity: High (Critical in high-risk code paths)
Required:
- SHOULD avoid importing
unsafein application code unless absolutely necessary. - If
unsafeis used, MUST treat it as “manual memory safety” requiring careful review and test coverage. - If
cgois used, MUST treat the C/C++ boundary as memory-unsafe; apply secure coding practices on the C side and isolate where possible.
Insecure patterns:
- Widespread
unsafe.Pointercasts in parsing, serialization, auth, or network code. cgoused for parsing or security boundaries without sandboxing.
Detection hints:
- Search for
import "unsafe",unsafe.Pointer,// #cgo,import "C". - Prioritize review where unsafe touches untrusted input.
Fix:
- Replace unsafe/cgo usage with safe standard library alternatives where possible.
- Isolate unsafe code in small, well-tested modules with fuzz/race tests.
Notes:
- The unsafe package explicitly provides operations that step around Go’s type safety guarantees.
--------------------------------------------------------------------
5) Practical scanning heuristics (how to “hunt”)
When actively scanning, use these high-signal patterns:
Toolchain & dependencies:
FROM golang:(Dockerfiles),go-version:(CI),toolchain go(go.mod), pinned old versionsGOSUMDB=off,GOINSECURE,GONOSUMDB,GOPROXY=directreplacedirectives ingo.modto forks/pathsgovulncheckmissing in CI
HTTP server hardening:
http.ListenAndServe(,ListenAndServeTLS(,&http.Server{with missing timeoutsReadHeaderTimeout: 0,ReadTimeout: 0,WriteTimeout: 0,IdleTimeout: 0, missingMaxHeaderBytes
Body parsing / DoS:
io.ReadAll(r.Body),json.NewDecoder(r.Body)without size capParseMultipartForm,FormFile,multipart.NewReaderwithout explicit limits- Missing
http.MaxBytesReader
Debug exposure:
import _ "net/http/pprof"/debug/pprof,/debug/vars
Templates / XSS / SSTI:
text/templateused for HTML outputtemplate.HTML(,template.JS(,template.URL(with user-controlled data.Parse(on user-controlled strings
Files:
http.ServeFile(with user pathhttp.FileServer(http.Dir(pointing at repo root or uploadsos.Open(filepath.Join(base, user))without containment checks
Injection:
- SQL building with
fmt.Sprintf, string concatenation neardb.Query/Exec exec.Command("sh","-c", ...),exec.Command("bash","-c", ...)
SSRF / outbound HTTP:
http.Get(userURL),client.Do(req)where URL comes from request/DB- Missing client timeout, missing
resp.Body.Close(), unboundedio.ReadAll(resp.Body)
Crypto:
math/randin token/session generationInsecureSkipVerify: true- Password hashing with
sha256/md5instead of bcrypt/argon2
Concurrency:
- Shared maps/slices mutated from handlers without locks
- CI lacking
go test -race
Always try to confirm:
- data origin (untrusted vs trusted)
- sink type (template/SQL/subprocess/files/http)
- protective controls present (limits, validation, allowlists, middleware, network controls)
--------------------------------------------------------------------
6) Sources (accessed 2026-01-28)
Primary Go documentation:
- Go Security Policy — https://go.dev/doc/security/policy
- Go Release History (security fixes in patch releases) — https://go.dev/doc/devel/release
- Go 1.25 Release Notes — https://go.dev/doc/go1.25
- net/http (server timeouts, MaxHeaderBytes, DefaultClient) — https://pkg.go.dev/net/http
- html/template (auto-escaping and trusted-template assumptions) — https://pkg.go.dev/html/template
- crypto/tls (MinVersion defaults, InsecureSkipVerify warnings) — https://pkg.go.dev/crypto/tls
- crypto/rand (secure randomness, token helpers) — https://pkg.go.dev/crypto/rand
- crypto/subtle (constant-time comparisons) — https://pkg.go.dev/crypto/subtle
- os/exec (no shell by default; command execution guidance) — https://pkg.go.dev/os/exec
- unsafe (bypasses type safety) — https://go.dev/src/unsafe/unsafe.go
- net/http/pprof (debug endpoints) — https://pkg.go.dev/net/http/pprof
- cmd/go (module authentication via go.sum/checksum DB; env vars like GOINSECURE) — https://pkg.go.dev/cmd/go
- Module Mirror and Checksum Database Launched (Go blog) — https://go.dev/blog/module-mirror-launch
- govulncheck documentation — https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck
- Go Race Detector documentation — https://go.dev/doc/articles/race_detector
- bcrypt (password hashing) — https://pkg.go.dev/golang.org/x/crypto/bcrypt
- Go vulnerability entry example (multipart resource consumption) — https://pkg.go.dev/vuln/GO-2023-1569
OWASP Cheat Sheet Series (general web security):
- Session Management — https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html
- CSRF Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html
- SSRF Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html
- XSS Prevention — https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html
- HTTP Security Response Headers — https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html
Express (Node.js) Web Security Spec (Express 5.x / 4.19.2+, Node.js LTS)
This document is designed as a security spec that supports:
1. Secure-by-default code generation for new Express apps and routes. 2. Security review / vulnerability hunting in existing Express code (passive “notice issues while working” and active “scan the repo and report findings”).
It 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).
---
0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)
- MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session secrets, cookies, tokens).
- 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).
- MUST provide evidence-based findings during audits: cite file paths, code snippets, middleware/config values, and runtime assumptions that justify the claim.
- 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.”
- 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])
---
1) Operating modes
1.1 Generation mode (default)
When asked to write new Express code or modify existing code:
- MUST follow every MUST requirement in this spec.
- SHOULD follow every SHOULD requirement unless the user explicitly says otherwise.
- MUST prefer safe-by-default APIs and proven libraries over custom security code.
- 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.).
1.2 Passive review mode (always on while editing)
While working anywhere in an Express repo (even if the user did not ask for a security scan):
- MUST “notice” violations of this spec in touched/nearby code.
- SHOULD mention issues as they come up, with a brief explanation + safe fix.
1.3 Active audit mode (explicit scan request)
When the user asks to “scan”, “audit”, or “hunt for vulns”:
- MUST systematically search the codebase for violations of this spec.
- MUST output findings in a structured format (see §2.3).
Recommended audit order:
1. Entrypoints (server/app bootstrap), deployment manifests, Dockerfiles, process manager config, CI/CD. 2. Express settings + middleware stack order (helmet, parsers, auth, sessions, CSRF, CORS). 3. Proxy trust (trust proxy) and IP/protocol/host handling. ([Express][2]) 4. Auth flows, sessions, cookies, password reset links, redirect handling. ([Express][1]) 5. State-changing routes + CSRF protections (cookie-authenticated apps). ([OWASP Cheat Sheet Series][3]) 6. Template rendering and XSS defenses (HTML generation, CSP, res.locals). ([OWASP Cheat Sheet Series][4]) 7. File handling (uploads + downloads + static files) and path traversal. ([Express][5]) 8. Injection classes (SQL, NoSQL, command execution, unsafe deserialization). ([OWASP Cheat Sheet Series][6]) 9. Outbound requests (SSRF) and webhook/callback delivery. ([OWASP Cheat Sheet Series][7]) 10. Rate limiting / brute-force defenses / abuse controls. ([Express][1]) 11. Dependency hygiene / lockfiles / npm audit / vulnerable Express versions. ([Express][1])
---
2) Definitions and review guidance
2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)
In Express, common untrusted inputs include:
req.params(route parameters)req.query(query string parameters; can be strings/arrays/objects depending on parsing) ([OWASP Cheat Sheet Series][8])req.bodyfromexpress.json(),express.urlencoded(),express.text(),express.raw()([Express][5])req.headers/req.get(...)req.cookies/req.signedCookies(if cookie parsing middleware is used)- Upload metadata and filenames (e.g., multer
file.originalname,file.mimetype) - Any data from external systems (webhooks, third-party APIs, message queues)
- Any persisted user content (DB rows) that originated from users
Special proxy note:
- If
trust proxyis enabled, values likereq.ip,req.hostname, andreq.protocolmay be derived fromX-Forwarded-*headers which can be attacker-controlled if your proxy chain is not correctly overwriting/removing them. ([Express][2])
2.2 State-changing request
A 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.
2.3 Required audit finding format
For each issue found, output:
- Rule ID:
- Severity: Critical / High / Medium / Low
- Location: file path + function/route/middleware name + line(s)
- Evidence: the exact code/config snippet
- Impact: what could go wrong, who can exploit it
- Fix: safe change (prefer minimal diff)
- Mitigation: defense-in-depth if immediate fix is hard
- False positive notes: what to verify if uncertain
---
3) Secure baseline: minimum production configuration (MUST in production)
This is the smallest “production baseline” that prevents common Express misconfigurations.
Minimum baseline targets:
helmet()is used and configured (especially CSP where applicable), and fingerprinting is reduced (disablex-powered-by). ([Express][1])- A custom 404 handler and a custom error handler exist, and production does not leak internal stack traces. ([Express][1])
- Cookie/session usage is deliberate:
- Not using default session cookie names
- Cookies use secure attributes (
Secure,HttpOnly,SameSite) as appropriate - Cookie-backed sessions never store secrets (they are readable by the client)
- Server-side sessions never use MemoryStore in production. ([Express][1])
- Request body parsing has explicit limits (
express.json({ limit }),express.urlencoded({ limit, parameterLimit, depth })). ([Express][5]) trust proxyis configured explicitly to match your proxy topology; not blindlytrue. ([Express][2])- Login/auth endpoints have brute-force protection and rate limiting. ([Express][1])
- Dependencies are regularly audited/updated (
npm audit+ advisory response). ([Express][1])
---
4) Rules (generation + audit)
Each rule contains: required practice, insecure patterns, detection hints, and remediation.
EXPRESS-INPUT-001: Treat all user input as untrusted and validate it
Severity: High
Required:
- 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.
- SHOULD apply allowlists (known-good) rather than blocklists when feasible.
- MUST reject or safely handle unexpected types/shapes in
req.query,req.params, andreq.body.
Insecure patterns:
- Passing
req.query,req.params,req.bodydirectly into database/query builders, redirects, filesystem paths, or templates. - Assuming
req.query.foois always a string (it can be an array/object depending on parsing). ([OWASP Cheat Sheet Series][8])
Detection hints:
- Identify “untrusted-to-sink” flows: request → sink (
res.redirect, SQL execution,sendFile,child_process, template render, outbound fetch). - Search for direct usage of
req.query.*,req.body.*,req.params.*in sensitive calls.
Fix:
- Add schema validation (e.g., zod/joi/express-validator) at route boundaries.
- Normalize types (e.g., force IDs to integers; reject arrays when scalar expected).
Notes:
- Express production security guidance explicitly says input validation/handling is the application’s responsibility. ([Express][1])
---
EXPRESS-REDIRECT-001: Prevent open redirects; validate redirect targets
Severity: Medium
Required:
- MUST validate redirect destinations derived from untrusted input (
next,return_to,url). - SHOULD allowlist only same-site relative paths (preferred) or a strict allowlist of domains.
- MUST fall back to a safe default when validation fails.
Insecure patterns:
res.redirect(req.query.next)with no validation.res.redirect(req.body.url)orres.location(...)using untrusted URLs.
Detection hints:
- Search for
res.redirect(andres.location(and trace the source of the target. - Look for query params named
next,redirect,return,url.
Fix:
- Only allow relative paths (starting with
/) and disallow//, backslashes, and encoded variants. - If cross-domain redirects are required, allowlist exact hosts and enforce
https.
Notes:
- Express documentation calls out open redirects as dangerous user input and shows validating the host before redirecting. ([Express][1])
- Keep Express updated: Express has had an open-redirect-related CVE affecting some versions, and upgrades are part of the mitigation posture. ([NVD][9])
---
EXPRESS-HEADERS-001: Use Helmet (or equivalent) to set essential security headers
Severity: Medium
Required:
- SHOULD use
helmet()to set common security headers. - SHOULD configure CSP realistically (avoid
unsafe-inlinewhere possible) for pages that render user-influenced content. - SHOULD set
X-Content-Type-Options: nosniff, clickjacking defenses (X-Frame-Optionsor CSPframe-ancestors), and appropriate referrer policy.
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.
Insecure patterns:
- No security headers set in app code and no evidence they are set at the edge.
- CSP missing on apps that display user content.
- Misconfigured framing headers that unintentionally allow clickjacking.
Detection hints:
- Search for
helmet(usage; check if CSP is configured or disabled. - Search for
res.setHeader(/res.set(for security header setting. - If not visible in app code, check nginx/CDN config; otherwise flag “verify at edge.”
Fix:
- Add
helmet()early in middleware order and configure:
- CSP (
contentSecurityPolicy) - Frame protections (
frameguardor CSPframe-ancestors) X-Content-Type-Options(noSniff)
Notes:
- Express production security best practices recommend Helmet and list headers Helmet sets by default. ([Express][1])
- OWASP HTTP Headers guidance is a useful reference when tuning policies. ([OWASP Cheat Sheet Series][10])
---
EXPRESS-FINGERPRINT-001: Reduce fingerprinting by disabling x-powered-by and customizing error/404 responses
Severity: Low (defense-in-depth)
Required:
- SHOULD disable
X-Powered-Byusingapp.disable('x-powered-by'). - SHOULD provide a custom 404 handler and a custom error handler to avoid distinct default responses and to control information leakage.
Insecure patterns:
- Default
X-Powered-By: Expressheader left enabled. - Default Express 404/error responses in production with identifiable formatting and/or stack traces.
Detection hints:
- Search for
app.disable('x-powered-by'). - Check middleware tail for a custom 404 (
app.use((req,res)=>...)) and a custom error handler (app.use((err,req,res,next)=>...)). - Check if
NODE_ENVis correctly set for production behavior (see EXPRESS-ERROR-001). ([Express][11])
Fix:
- Add:
app.disable('x-powered-by')- A custom 404 handler
- A custom error handler that logs server-side and returns generic messages client-side
Notes:
- Express docs explicitly recommend disabling
x-powered-byand adding your own not-found and error handlers. ([Express][1])
---
EXPRESS-COOKIE-001: Cookies must use secure attributes and minimal scope
Severity: Medium
Required:
- MUST set cookie flags appropriately for any authentication/session cookie:
Securewhen HTTPS (production) IMPORTANT NOTE: Only setSecurein production environment if TLS is configured. When running in a local dev environment over HTTP, do not setSecureproperty on cookies. You should do this conditionally based on if the app is running in production mode. You should also include a property likeSESSION_COOKIE_SECUREwhich can be used to disableSecurecookies when testing over HTTP.HttpOnlyfor auth/session cookiesSameSiteset deliberately (Laxis a common baseline;Strictif compatible;Noneonly withSecureand a justified cross-site need)- SHOULD avoid setting
domainbroadly (avoid “all subdomains” unless required). - SHOULD set bounded expiry appropriate to risk and UX.
Insecure patterns:
- Session/auth cookies without
HttpOnly. - Cookies without
Securein production HTTPS. SameSite=None+ cookie-authenticated state-changing endpoints without CSRF protections.
Detection hints:
- Search for
res.cookie(,Set-Cookie,cookie: { ... },express-session,cookie-session. - Verify cookie flags in session middleware configuration.
Fix:
- Set these attributes centrally in session/cookie middleware configuration.
Notes:
- Express production security guidance lists cookie security options (
secure,httpOnly, etc.). ([Express][1]) res.cookie()ultimately setsSet-Cookiewith options; defaults follow RFC 6265 behavior when options are omitted. ([Express][5])- OWASP session management guidance is relevant for choosing flags and lifetimes. ([OWASP Cheat Sheet Series][12])
---
EXPRESS-SESS-001: Do not use the default session cookie name; avoid session fingerprinting
Severity: Low (defense-in-depth)
Required:
- SHOULD override the default session cookie name (e.g., do not keep
connect.sidwhen usingexpress-session). - SHOULD use a generic name (e.g.,
sessionId) unless you have a compatibility reason.
Insecure patterns:
express-sessionused with noname:configured (default cookie name).- Multiple apps on the same domain sharing a cookie name accidentally.
Detection hints:
- Search for
express-sessionconfig blocks; check forname:.
Fix:
- Set
name: 'sessionId'(or similar) inexpress-sessionoptions.
Notes:
- Express docs explicitly recommend not using the default session cookie name to reduce fingerprinting. ([Express][1])
---
EXPRESS-SESS-002: Session storage and lifecycle must be production-safe
Severity: High
Required:
- MUST NOT use
MemoryStorein production (it is not designed for production use). - MUST store session secrets outside source control and rotate them safely.
- SHOULD regenerate sessions on login / privilege changes to reduce session fixation risk.
- MUST NOT store sensitive secrets in client-readable cookie sessions.
Insecure patterns:
app.use(session({ store: new MemoryStore(), ... }))or missing store (defaults to MemoryStore).- Hard-coded for example:
secret: 'keyboard cat'/secret: 's3Cur3'in repo. - Using
cookie-sessionto store access tokens, refresh tokens, or PII.
Detection hints:
- Search for
express-sessionand look forMemoryStoreusage or missingstore. - Search for
secret:in session config and check if it’s hard-coded. - Look for
req.session = ...patterns and whether sensitive data is stored.
Fix:
- Use a production session store (Redis, database-backed, etc.).
- Load secrets from environment/secret manager.
- On login:
req.session.regenerate(...)or equivalent flow with safe privilege re-binding.
Notes:
express-sessionexplicitly warns thatMemoryStoreis not designed for production. ([Express][1])express-sessiondocuments rotating secrets and session regeneration to guard against fixation. ([Express][1])- 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])
---
EXPRESS-CSRF-001: Cookie-authenticated state-changing requests MUST be CSRF-protected
Severity: High
- 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.
Required:
- MUST protect all state-changing endpoints (POST/PUT/PATCH/DELETE) that rely on cookies for authentication.
- SHOULD use a well-understood CSRF mitigation (token-based is the typical baseline).
- 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.
- 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.
IMPORTANT NOTE:
- If authentication is done via
Authorization: Bearer ...headers (and not cookies), classic browser CSRF is typically not applicable;
Insecure patterns:
- Cookie-authenticated endpoints that change state with no CSRF protection.
- Using GET for state-changing actions (amplifies CSRF risk).
- “CSRF protection” that only checks a user-controlled field.
Detection hints:
- Enumerate routes with methods other than GET/HEAD and identify whether cookies gate auth.
- Look for presence/absence of CSRF middleware and token checks.
- Check JSON APIs too, not only HTML forms.
Fix:
- Implement CSRF tokens for cookie-authenticated flows.
- Add Origin/Referer checks where feasible, and ensure SameSite is set appropriately.
Notes:
- 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])
---
EXPRESS-CORS-001: CORS must be explicit and least-privilege
Severity: Medium (High if misconfigured with credentials)
Required:
- If CORS is not needed, MUST keep it disabled.
- If CORS is needed:
- MUST allowlist trusted origins (do not reflect arbitrary
Originwithout validation). - MUST NOT combine broad origins with credentialed cookies (
Access-Control-Allow-Credentials: true). - SHOULD restrict methods, headers, and exposed headers to what’s required.
Insecure patterns:
Access-Control-Allow-Origin: *withAccess-Control-Allow-Credentials: true.- Reflecting
Originfor all requests without allowlist validation. - Applying permissive CORS middleware globally when only a subset needs cross-origin access.
Detection hints:
- Search for
cors(,Access-Control-Allow-Origin,Access-Control-Allow-Credentials. - Inspect whether cookies are used for auth on endpoints exposed cross-origin.
Fix:
- Implement strict origin allowlist and ensure credentialed requests only for intended origins.
- Consider splitting CORS config per route group rather than global.
Notes:
- 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])
---
EXPRESS-PROXY-001: Reverse proxy trust (trust proxy) must be configured correctly
Severity: Medium (High if using IP based authentication)
Required:
- If behind a reverse proxy/LB, MUST configure
app.set('trust proxy', ...)to match the real proxy chain. - MUST NOT blindly set
trust proxy = trueunless you fully control the proxy behavior and header rewriting. - MUST ensure the last trusted proxy overwrites/removes
X-Forwarded-For,X-Forwarded-Host, andX-Forwarded-Protoso clients cannot spoof them.
Insecure patterns:
app.set('trust proxy', true)in an app directly exposed to the internet or behind unknown proxies.- Using
req.ip,req.protocol,req.hostnamefor security decisions without correct proxy trust configuration. - Rate limiting keyed by
req.ipwith spoofable forwarded headers.
Detection hints:
- Search for
app.set('trust proxy'. - Check infra docs (nginx/LB) for header rewriting behavior.
- Identify any security logic using
req.ip,req.ips,req.protocol,req.hostname.
Fix:
- Set
trust proxyto a hop count, explicit IP/subnet list, or a custom function matching your network. - Ensure proxies overwrite forwarded headers.
Notes:
- Express explicitly warns that when
trust proxyistrue, the client IP is derived fromX-Forwarded-For, and if proxies don’t overwrite forwarded headers, the client can provide any value. It also describes that enabling trust proxy impactsreq.hostnameandreq.protocolderived from forwarded headers. ([Express][2])
---
EXPRESS-BODY-001: Request body size and parsing limits MUST be set appropriately
Severity: Low
Required:
- SHOULD set explicit body size limits for:
express.json({ limit })express.urlencoded({ limit, parameterLimit, depth })- SHOULD only enable the parsers you need; do not parse large bodies by default for all routes.
- SHOULD enforce additional limits at the reverse proxy / gateway level.
Insecure patterns:
- No explicit body limits (accepting arbitrarily large JSON/urlencoded).
- Global parsers applied to all routes when only some need bodies.
parameterLimitvery high without justification (DoS potential).
Detection hints:
- Search for
express.json(and confirmlimitis set (or consciously accepted). - Search for
express.urlencoded(and inspectlimit,parameterLimit, anddepth. - Review upload/webhook endpoints for special parsing needs.
Fix:
- Configure parsers with conservative defaults and override per route group when needed.
Notes:
- Express documents
express.jsonoptions (includinglimit, defaulting to 100kb) and explicitly notesreq.bodyis untrusted and should be validated. ([Express][5]) - Express documents
express.urlencodedoptions includinglimit,parameterLimit, anddepth. ([Express][5]) - OWASP Node.js guidance also recommends setting request size limits. ([OWASP Cheat Sheet Series][8])
---
EXPRESS-INPUT-002: Prevent HTTP Parameter Pollution and type confusion in req.query
Severity: Medium
Required:
- MUST treat
req.queryvalues as potentially multi-valued (array/object), depending on query parsing. - SHOULD reject ambiguous multi-valued parameters for security-sensitive fields (e.g.,
role,isAdmin,redirect,amount,userId). - SHOULD consider explicit parsing or dedicated middleware if parameter pollution is a concern.
Insecure patterns:
if (req.query.admin) { ... }without type checks (arrays/objects may coerce truthy).- Passing
req.querydirectly into ORM/NoSQL query objects.
Detection hints:
- Search for security-sensitive comparisons on
req.query.*without type enforcement. - Look for code that assumes query params are strings.
Fix:
- Validate shape: enforce string-only for certain params and reject arrays/objects.
- Normalize query parsing settings (simple vs extended) where applicable and documented.
Notes:
- 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])
---
EXPRESS-XSS-001: Prevent reflected/stored XSS in HTML responses and templating
Severity: High
Required:
- MUST escape untrusted content in HTML output (templates should auto-escape by default; do not bypass).
- MUST NOT inject untrusted strings into HTML without escaping/sanitization.
- SHOULD set CSP (via Helmet) for apps rendering user-controlled content.
- SHOULD keep
res.localsfree of user-controlled input intended for templates unless it is validated/escaped.
Insecure patterns:
res.send("<div>" + req.query.q + "</div>")- Passing untrusted HTML through “safe” template flags/filters.
- Writing untrusted strings into
res.localsand then rendering without escaping.
Detection hints:
- Search for
res.send(with strings containing user input. - Search for template “safe” flags (engine-specific) and trace data origin.
- Search for assignments to
res.localsand whether they might contain untrusted data.
Fix:
- Use a template engine with autoescaping; pass only validated data.
- For rich text that must contain HTML, use a trusted sanitizer and an allowlist policy.
- Add CSP with realistic directives.
Notes:
- 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]) - OWASP XSS prevention guidance provides standard output-encoding and policy recommendations. ([OWASP Cheat Sheet Series][4])
- Helmet can mitigate some XSS classes via headers such as CSP. ([Express][1])
---
EXPRESS-TEMPLATE-001: Never render untrusted templates or template paths (SSTI / LFI risk)
Severity: Critical (if you can prove template strings/paths are user/attacker-controlled)
Required:
- MUST NOT render templates whose contents or template path/name is influenced by untrusted input.
- MUST NOT load templates from user-controlled filesystem locations.
- SHOULD treat “email template editors”, “theme engines”, and “CMS-like template storage” as high-risk designs requiring sandboxing and isolation.
Insecure patterns:
res.render(req.query.view, data)whereviewis not allowlisted.- Rendering a template from a string that includes user input (engine-specific).
- Loading templates from uploads directories.
Detection hints:
- Search for
res.render(where the first argument is derived from request/DB without allowlist. - Search for template compilation APIs (engine-specific) fed by user content.
Fix:
- Use allowlisted template names and a fixed templates directory.
- If user-defined templates are required, implement strict sandboxing and isolate execution.
Notes:
- Express’s template system depends on the chosen engine; assume unsafe if user input influences template selection or source.
---
EXPRESS-FILES-001: Prevent path traversal and unsafe file serving (sendFile/download)
Severity: High
Required:
- MUST NOT pass user-controlled filesystem paths directly to
res.sendFile()/res.download()/ filesystem APIs. - SHOULD use
res.sendFilewith a fixedrootand strict options (e.g., deny dotfiles) when serving user-selected files from a directory. - MUST enforce authorization checks before serving user-specific files.
Insecure patterns:
res.sendFile(req.query.path)orres.download(req.params.file)with no root restriction.- File-serving routes that accept
..segments, encoded traversal, or absolute paths.
Detection hints:
- Search for
res.sendFile(and trace thepathargument origin. - Search for
res.download(and trace thepathargument origin. - Look for
fs.readFile/createReadStreamon paths derived from requests.
Fix:
- Use an identifier-to-path mapping stored server-side (DB), not raw paths from clients.
- Use
root: <trusted_base_dir>anddotfiles: 'deny'where appropriate; validate the filename component strictly.
Notes:
- Express’s
res.sendFiledocs show using arootoption anddotfiles: 'deny'as part of a safe serving configuration. ([Express][5]) res.downloadtransfers the file as an attachment, but you still must control/validate the underlyingpath. ([Express][5])
---
EXPRESS-STATIC-001: Harden express.static / serve-static and never serve untrusted uploads as active content
Severity: Medium (if serving untrusted user files if there are not robust limits tot eh file extensions)
Required:
- 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.
- SHOULD configure static serving to:
- deny/ignore dotfiles
- avoid unintended directory indexes if not needed
- apply appropriate cache controls for immutable assets
Insecure patterns:
app.use(express.static('uploads'))where users can upload arbitrary files.- Serving uploaded HTML or SVG inline from the same origin as the app.
Detection hints:
- Search for
express.static(and identify served directories. - Compare served directories with upload storage locations.
- Check for
dotfilesandindexoptions in static middleware.
Fix:
- Store uploads outside any static web root and serve via controlled routes that set safe
Content-TypeandContent-Disposition: attachmentwhen appropriate. - Configure
express.static(root, { dotfiles: 'deny'|'ignore', index: false (if desired) }).
Notes:
- Express documents
express.staticoptions, includingdotfilesbehavior andindex. ([Express][5])
---
EXPRESS-UPLOAD-001: File uploads must be validated, stored safely, and served safely
Severity: Low - Medium
Required:
- SHOULD enforce upload size limits (app + edge).
- MUST validate file type using allowlists and content checks (not only filename extension).
- MUST store uploads outside executable/static roots when possible.
- SHOULD generate server-side filenames (random IDs); do not trust original names.
- MUST serve potentially active formats safely (download attachment) unless explicitly intended.
Insecure patterns:
- Accepting arbitrary file types and serving them back inline.
- Using
file.originalnameas the storage path. - Missing size/type validation.
Detection hints:
- Look for multer/busboy/formidable usage and check for
limits. - Check where uploaded files are written and how they are served.
- Check whether uploads end up under
public/or anyexpress.staticroot.
Fix:
- Implement allowlist validation + safe storage + safe serving, per OWASP upload guidance.
Notes:
- OWASP File Upload guidance covers allowlists, content validation, storage, and safe serving patterns. ([OWASP Cheat Sheet Series][13])
---
EXPRESS-INJECT-001: Prevent SQL injection (use parameterized queries / ORM)
Severity: High
Required:
- MUST use parameterized queries or an ORM/query builder that parameterizes under the hood.
- MUST NOT build SQL via string concatenation/template literals with untrusted input.
Insecure patterns:
- `
db.query(SELECT * FROM users WHERE id = ${req.query.id})` "SELECT ... WHERE name = '" + req.body.name + "'"
Detection hints:
- Grep for
SELECT,INSERT,UPDATE,DELETEstrings in JS/TS. - Trace untrusted input into
.query(...),.execute(...), or raw SQL APIs.
Fix:
- Replace with parameterized queries (placeholders) or ORM query APIs.
- Validate types (e.g., integer IDs) before querying.
Notes:
- OWASP SQL injection prevention guidance strongly favors parameterized queries. ([OWASP Cheat Sheet Series][6])
---
EXPRESS-INJECT-002: Prevent NoSQL injection / operator injection (Mongo-style)
Severity: High (app-dependent)
Required:
- MUST validate types and schemas for any query object built from untrusted input.
- MUST prevent operator injection (e.g.,
$ne,$gt,$where) if user input is merged into query objects. - SHOULD consider defensive libraries/middleware when appropriate.
Insecure patterns:
collection.find(req.body)where the body is attacker-controlled.- Merging
req.query/req.bodyinto Mongo queries without schema validation.
Detection hints:
- Search for
find(,findOne(,aggregate(calls where argument is request-derived. - Check for patterns like
{ ...req.query }orObject.assign(query, req.body).
Fix:
- Use schema validation at boundary; explicitly construct query objects from validated fields only.
Notes:
- 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])
---
EXPRESS-CMD-001: Prevent OS command injection (child_process)
Severity: Critical to High (depends on exposure), please prove it is user/attacker controlled
Required:
- MUST avoid executing shell commands with untrusted input.
- If subprocess is necessary:
- MUST avoid
exec()/execSync()with attacker-influenced strings - MUST NOT use
shell: truewith attacker-influenced data - 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. - SHOULD place user-controlled values after
--when supported by the subcommand to avoid flag injection
Insecure patterns:
exec(req.query.cmd)exec(convert ${userPath} ...)spawn('sh', ['-c', userString])spawn(userString, ['foo'])
Detection hints:
- Search for
child_process,exec(,execSync(,spawn(,fork(. - Trace request/DB data into command construction.
Fix:
- If possible, write the functionality in javascript or use a library instead of subprocess.
- If unavoidable, hard-code command and strictly allowlist parameters.
Notes:
- OWASP OS command injection defense guidance covers avoid-shell and allowlist patterns. ([OWASP Cheat Sheet Series][14])
---
EXPRESS-SSRF-001: Prevent server-side request forgery (SSRF) in outbound HTTP
Severity: Medium (High in cloud/LAN deployments)
NOTE: 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).
Required:
- MUST treat outbound requests to user-provided URLs as high risk if there are other reachable private http endpoints.
- SHOULD validate and restrict destinations (allowlist hosts/domains) for any user-influenced URL fetch.
- SHOULD block access to:
- localhost / private IP ranges / link-local
- cloud metadata endpoints
- MUST allow only
http/httpsfor URL fetch features (to avoid schemas such asfile:,javascript:) - SHOULD set timeouts and restrict redirects.
Insecure patterns:
fetch(req.query.url)- “URL preview” / “import from URL” endpoints that accept arbitrary URLs.
Detection hints:
- Search for
fetch(,axios(,got(,request(,node-fetchusage where URL originates from users/DB. - Review webhook testers, previewers, image fetchers.
Fix:
- Enforce scheme allowlist, host allowlist, DNS/IP resolution checks, timeouts, and redirect policy.
- Consider network egress controls at infrastructure level.
Notes:
- OWASP SSRF prevention guidance provides standard controls and common pitfalls. ([OWASP Cheat Sheet Series][7])
---
EXPRESS-ERROR-001: Error handling MUST not leak sensitive details in production
Severity: Low
Required:
- SHOULD define a centralized error handler (
app.use((err, req, res, next) => ...)) at the end of middleware. - MUST avoid returning stack traces, internal error messages, or secrets to clients in production.
- SHOULD log errors server-side with appropriate redaction.
- SHOULD ensure the app runs with production settings so default behavior doesn’t leak details.
- MUST avoid logging or returning sensitive information such as secrets, env vars, sessions, cookies in error messages in production.
Insecure patterns:
- Returning
err.stackto clients. - Using dev-only error middleware in production.
NODE_ENVleft as development, causing verbose error responses.
Detection hints:
- Verify there is a final error-handling middleware.
- Search for
res.status(500).send(err)or similar. - Check production environment variables and startup scripts.
Fix:
- Add a production-safe error handler that returns generic messages and logs details internally.
- Ensure environment is configured for production behavior.
Notes:
- Express production security guidance recommends custom error handling. ([Express][1])
- Express error handling docs describe the default error handler behavior and how production mode affects what is exposed. ([Express][11])
---
EXPRESS-AUTH-001: Prevent brute-force attacks against authorization endpoints
Severity: Medium
NOTE: 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.
Required:
- SHOULD protect login/auth endpoints against brute forcing.
- SHOULD rate-limit by:
1. consecutive failed attempts per username+IP 2. failed attempts per IP over a time window
Insecure patterns:
- Unlimited login attempts.
Detection hints:
- Identify all auth endpoints and check for rate limiting/throttling.
- Search for
rate-limiter-flexible,express-rate-limit, or gateway policies.
Fix:
- Implement rate-limiting/throttling (app or edge). Express docs point to
rate-limiter-flexibleas a tool for this approach. ([Express][1])
Notes:
- OWASP Node.js cheat sheet also recommends precautions against brute forcing. ([OWASP Cheat Sheet Series][8])
---
EXPRESS-DEPS-001: Dependency and patch hygiene (Express + Node + critical middleware)
Severity: Medium / Low
NOTE: 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.
Do not upgrade packages without concent from the user. This may break existing code in unexpected ways. Instead, inform them of the outdated packages.
Required:
- MUST keep Express on a maintained version line (avoid EOL major versions).
- MAY use
npm auditin CI and during maintenance work. - SHOULD pin dependencies via lockfiles and review major updates carefully.
Insecure patterns:
- Running EOL Express versions (e.g., very old major lines).
- Ignoring
npm auditfindings without triage. - Unpinned dependency ranges that auto-upgrade into insecure versions.
Detection hints:
- Check
package.jsonand lockfiles forexpressversion and other critical middleware versions. - Inspect CI pipelines for
npm audit/SCA steps.
Fix:
- Upgrade to latest stable Express and apply patches.
- Add automated dependency scanning and upgrade process.
Notes:
- Express production security guidance emphasizes that dependency vulnerabilities can compromise the app, and recommends
npm audit. ([Express][1]) - Track security issues affecting Express versions (including known open-redirect-related CVEs). ([NVD][9])
---
EXPRESS-DOS-001: Configure DoS protections (timeouts, limits, reverse proxy)
Severity: Low
NOTE: 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.
Required:
- SHOULD use a reverse proxy to provide caching, load balancing, and filtering controls when feasible.
- MAY configure server/proxy timeouts and connection limits to reduce exposure to Slowloris and similar DoS patterns.
- MUST ensure server/socket errors are handled so malformed connections do not crash the process. (Express should handle exceptions, but there are edgecases)
Insecure patterns:
- No reverse proxy in front of a public Node server, with defaults everywhere.
- Missing error handlers on server/socket objects.
- Extremely permissive timeouts and unlimited body sizes.
Detection hints:
- Inspect server creation (
http.createServer,https.createServer) and whether timeouts are set. - Check proxy/gateway config for timeouts and max body size.
Fix:
- Explain how to configure reverse proxy and timeouts, set request size limits
- add robust error handling middleware
Notes:
- Node’s security guidance for HTTP DoS discusses using reverse proxies and correctly configuring server timeouts. ([Node.js][15])
---
EXPRESS-NODE-INSPECT-001: Do not expose the Node inspector in production
Severity: Critical
NOTE: Ensure that this detection is actually in the production path, and not just being used for local debugging.
Required:
- MUST NOT run Node with
--inspect(especially bound to non-loopback) in production. - MUST ensure
NODE_OPTIONSor startup scripts do not enable inspector in prod. - SHOULD firewall/debug locally only.
Insecure patterns:
node --inspect=0.0.0.0:9229 app.jsin production.- Container/PM2/systemd configs enabling inspector.
Detection hints:
- Search for
--inspectin Dockerfiles, Procfiles, systemd units, PM2 configs, npm scripts. - Check
NODE_OPTIONS.
Fix:
- Remove inspector flags from production start commands; restrict to local dev.
Notes:
- Node security guidance discusses inspector exposure risks (e.g., DNS rebinding) and recommends not running inspector in production. ([Node.js][15])
---
EXPRESS-NODE-HTTP-001: Do not enable insecure HTTP parsing in production
Severity: High
NOTE: Ensure that this detection is actually in the production path, and not just being used for local dev.
Required:
- MUST NOT use Node’s
insecureHTTPParserin production. - MAY suggest configuring front-end proxies to normalize ambiguous requests to reduce request smuggling risk.
Insecure patterns:
- Creating an HTTP server with
{ insecureHTTPParser: true }.
Detection hints:
- Search for
insecureHTTPParserin server creation code.
Fix:
- Remove insecure parsing; rely on spec-compliant parsing and normalize at the edge.
Notes:
- Node security guidance explicitly recommends not using
insecureHTTPParser. ([Node.js][15])
---
5) Practical scanning heuristics (how to “hunt”)
When actively scanning an Express repo, these patterns are high-signal:
- TLS / transport:
app.listen(80without reverse proxy mention; missinghelmet; cookies missingsecure([Express][1]) (NOTE this only applies to web facing applications, internal apps likely won't have TLS)- Proxy trust:
app.set('trust proxy', true); logic usingreq.ip/req.protocol/req.hostname([Express][2])- Security headers / fingerprinting:
- missing
helmet(; missingapp.disable('x-powered-by')([Express][1]) - Cookies / sessions:
express-sessionwith missingstore(MemoryStore risk), hard-codedsecret:, missingcookie: { secure/httpOnly/sameSite }([Express][1])cookie-sessionstoring large objects or secrets ([Express][1])- Body parsing limits:
express.json()orexpress.urlencoded()withoutlimit/parameterLimit/depth([Express][5])- CSRF:
- POST/PUT/PATCH/DELETE routes using cookie auth with no CSRF tokens/origin checks ([OWASP Cheat Sheet Series][3])
- Open redirects:
res.redirect(req.query.next)or similar ([Express][1])- XSS / HTML output:
res.send(building HTML with user input; template “safe” flags; untrusted values inres.locals([Express][5])- File handling:
res.sendFile(/res.download(where path originates from request;express.static('uploads')([Express][5])- Injection:
- SQL strings + template literals into DB calls ([OWASP Cheat Sheet Series][6])
child_process.exec/execSync/shell: true([OWASP Cheat Sheet Series][14])- SSRF:
- outbound
fetch/axios/gotto user-provided URLs ([OWASP Cheat Sheet Series][7]) - Brute force / abuse:
- auth endpoints lacking throttling; no rate limiting middleware ([Express][1])
- Supply chain:
- outdated Express versions; no lockfiles; no
npm auditworkflow ([Express][1]) - Node runtime hazards:
--inspectin production scripts;insecureHTTPParserusage ([Node.js][15])
Always try to confirm:
- data origin (untrusted vs trusted)
- sink type (HTML/template, SQL/NoSQL, subprocess, filesystem, redirect, outbound HTTP)
- protective controls present (validation, allowlists, middleware, proxy config, header policies)
- whether protections are at the edge vs in app code
---
6) Sources (accessed 2026-01-27)
Primary Express documentation:
- Express: Production Best Practices — Security:
https://expressjs.com/en/advanced/best-practice-security.html([Express][1]) - Express: Behind Proxies (
trust proxy):https://expressjs.com/en/guide/behind-proxies.html([Express][2]) - Express 5.x API Reference (parsers, static, sendFile, redirect, cookies):
https://expressjs.com/en/5x/api.html([Express][5]) - Express: Error Handling:
https://expressjs.com/en/guide/error-handling.html([Express][11])
Session middleware documentation:
- express-session docs (cookie flags, secret rotation, fixation mitigation, MemoryStore warning):
https://expressjs.com/en/resources/middleware/session.html([Express][1])
Node.js and npm official references:
- 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]) - npm Docs —
npm audit:https://docs.npmjs.com/cli/v9/commands/npm-audit/([npm Docs][16])
OWASP Cheat Sheet Series:
- Session Management:
https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html([OWASP Cheat Sheet Series][12]) - CSRF Prevention:
https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html([OWASP Cheat Sheet Series][3]) - XSS Prevention:
https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html([OWASP Cheat Sheet Series][4]) - Input Validation:
https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html([OWASP Cheat Sheet Series][17]) - SQL Injection Prevention:
https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html([OWASP Cheat Sheet Series][6]) - OS Command Injection Defense:
https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html([OWASP Cheat Sheet Series][14]) - SSRF Prevention:
https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html([OWASP Cheat Sheet Series][7]) - File Upload:
https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html([OWASP Cheat Sheet Series][13]) - Unvalidated Redirects:
https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html([OWASP Cheat Sheet Series][18]) - HTTP Headers:
https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html([OWASP Cheat Sheet Series][10])
Versioning / advisories:
- Express package version (npm):
https://www.npmjs.com/package/express - Express open redirect advisory (CVE):
https://nvd.nist.gov/vuln/detail/CVE-2024-29041([NVD][9])
[1]: https://expressjs.com/en/advanced/best-practice-security.html "Security Best Practices for Express in Production" [2]: https://expressjs.com/en/guide/behind-proxies.html "Express behind proxies" [3]: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html "Cross-Site Request Forgery Prevention - OWASP Cheat Sheet Series" [4]: https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html "Cross Site Scripting Prevention - OWASP Cheat Sheet Series" [5]: https://expressjs.com/en/5x/api.html "Express 5.x - API Reference" [6]: https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html "SQL Injection Prevention - OWASP Cheat Sheet Series" [7]: https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html "Server Side Request Forgery Prevention - OWASP Cheat Sheet Series" [8]: https://cheatsheetseries.owasp.org/cheatsheets/Nodejs_Security_Cheat_Sheet.html "Nodejs Security - OWASP Cheat Sheet Series" [9]: https://nvd.nist.gov/vuln/detail/cve-2024-29041?utm_source=chatgpt.com "CVE-2024-29041 Detail - NVD" [10]: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html "HTTP Headers - OWASP Cheat Sheet Series" [11]: https://expressjs.com/en/guide/error-handling.html "Express error handling" [12]: https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html "Session Management - OWASP Cheat Sheet Series" [13]: https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html "File Upload - OWASP Cheat Sheet Series" [14]: https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html "OS Command Injection Defense - OWASP Cheat Sheet Series" [15]: https://nodejs.org/en/learn/getting-started/security-best-practices "Node.js — Security Best Practices" [16]: https://docs.npmjs.com/cli/v9/commands/npm-audit/ "npm-audit | npm Docs" [17]: https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html "Input Validation - OWASP Cheat Sheet Series" [18]: https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html "Unvalidated Redirects and Forwards - OWASP Cheat Sheet Series"
jQuery Frontend Security Spec (jQuery 4.0.x, modern browsers)
This document is designed as a security spec that supports:
1. Secure-by-default code generation for new jQuery-based frontend code. 2. Security review / vulnerability hunting in existing jQuery-based code (passive “notice issues while working” and active “scan the repo and report findings”).
It 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).
---
0) Safety, boundaries, and anti-abuse constraints (MUST FOLLOW)
- MUST NOT request, output, log, or commit secrets (API keys, passwords, private keys, session tokens, refresh tokens, CSRF tokens, session cookies).
- MUST treat the browser as an attacker-controlled environment:
- Frontend checks (UI gating, “disable button”, hidden fields, client-side validation) MUST NOT be treated as authorization or a security boundary.
- Server-side authorization and validation MUST exist even if frontend is “correct”.
- 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). - MUST provide evidence-based findings during audits: cite file paths, code snippets, and relevant configuration values.
- 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”.
---
1) Operating modes
1.1 Generation mode (default)
When asked to write new jQuery code or modify existing jQuery code:
- MUST follow every MUST requirement in this spec.
- SHOULD follow every SHOULD requirement unless the user explicitly says otherwise.
- MUST prefer safe-by-default patterns: text insertion, DOM node construction, allowlists, and proven sanitization libraries over custom escaping.
- MUST avoid introducing new risky sinks (HTML string building, dynamic script loading, JSONP, inline script/event-handler attributes, unsafe URL assignment, unsafe object merging).
1.2 Passive review mode (always on while editing)
While working anywhere in a repo that uses jQuery (even if the user did not ask for a security scan):
- MUST “notice” violations of this spec in touched/nearby code.
- SHOULD mention issues as they come up, with a brief explanation + safe fix.
1.3 Active audit mode (explicit scan request)
When the user asks to “scan”, “audit”, or “hunt for vulns”:
- MUST systematically search the codebase for violations of this spec.
- MUST output findings in the structured format (see §2.3).
Recommended audit order:
1. jQuery sourcing, versions, and dependency hygiene (script tags, lockfiles, CDN usage, SRI). 2. CSP / Trusted Types / security headers posture (in repo and at runtime if observable). 3. DOM XSS: untrusted sources → jQuery sinks (.html, .append, $("<…>"), .load, etc.). 4. Script execution sinks: JSONP, dataType:"script", $.getScript, dynamic <script> insertion. 5. URL/attribute assignment (href, src, style, on* attributes). 6. Prototype pollution / unsafe object merging ($.extend patterns). 7. AJAX auth patterns + CSRF for cookie-based sessions. 8. Third-party plugins and untrusted content rendering paths (comments, WYSIWYG, markdown-to-HTML).
---
2) Definitions and review guidance
2.1 Untrusted input (treat as attacker-controlled unless proven otherwise)
Examples include:
- Any data from the server that originates from users (user profiles, comments, “display name”, rich text, filenames).
- Data from third-party APIs or services.
- Browser-controlled sources:
location.href,location.search,location.hashdocument.URL,document.baseURI,document.referrerwindow.namelocalStorage/sessionStoragepostMessageevent data (unless strict origin and schema validation exists)- Any DOM content that could have been injected previously (stored XSS)
2.2 High-risk “sinks” in jQuery contexts
A sink is a code path where untrusted input can become interpreted as executable code or HTML.
Key jQuery sink categories:
- HTML insertion / parsing:
- DOM manipulation methods that accept HTML strings such as
.html(),.append(), and related methods (see CVE notes below). ([NVD][1]) $(htmlString)(when the argument can be interpreted as HTML markup).jQuery.parseHTML(html, …, keepScripts)especially withkeepScripts=true. ([jQuery API][2]).load(url)(loads HTML into DOM; has special script execution behavior). ([jQuery API][3])- Script execution / dynamic code loading:
$.getScript()/$.ajax({ dataType: "script" })(executes fetched JavaScript). ([jQuery API][4])- JSONP (
dataType: "jsonp"or implicit JSONP behavior) (executes remote JavaScript as a response). ([jQuery API][5]) eval,new Function,setTimeout("…"),setInterval("…"),$.globalEval(if present)- Dangerous attribute assignment:
- Assigning untrusted strings to
href,src,srcdoc,style, or event-handler attributes (onload,onclick, etc.) javascript:URLs are particularly dangerous and discouraged. ([MDN Web Docs][6])
2.3 Required audit finding format
For each issue found, output:
- Rule ID:
- Severity: Critical / High / Medium / Low
- Location: file path + function/component + line(s)
- Evidence: the exact code/config snippet
- Impact: what could go wrong, who can exploit it
- Fix: safe change (prefer minimal diff)
- Mitigation: defense-in-depth if immediate fix is hard
- False positive notes: what to verify if uncertain
---
3) Secure baseline: minimum production configuration (MUST in production)
This is the smallest “production baseline” that prevents common jQuery-related security failures.
3.1 Use a supported, patched jQuery version (MUST)
- MUST use a supported jQuery major version and keep it updated.
- As of 2026-01-27, the jQuery project ships jQuery 4.0.0 as the latest major release. ([blog.jquery.com][7])
- 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])
3.2 Load jQuery safely (MUST)
- MUST load jQuery only from:
- Your own build pipeline (bundled via npm/yarn + lockfile), or
- The official jQuery CDN / a trusted CDN with Subresource Integrity (SRI) enabled.
- If loading from a CDN, SHOULD use SRI (
integrity) and correctcrossoriginsettings; the jQuery project explicitly supports and recommends SRI on its CDN. (Retrieved from [jquery.com][8])
3.3 CSP + Trusted Types (SHOULD, and MUST where available/required by policy)
- SHOULD deploy a Content Security Policy (CSP) that reduces XSS impact (especially
script-srcrestrictions and avoidingunsafe-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. - SHOULD consider Trusted Types as a strong defense-in-depth against DOM XSS. ([W3C][10])
- If you deploy the CSP directive
require-trusted-types-for, then code MUST route DOM-injection through Trusted Types policies. ([MDN Web Docs][11]) - 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])
3.4 Security headers and cookie posture (defense in depth; SHOULD)
Even 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.
- SHOULD set common security headers (CSP,
X-Content-Type-Options: nosniff, clickjacking protection viaframe-ancestors/X-Frame-Options,Referrer-Policy). ([OWASP Cheat Sheet Series][12]) - 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.
---
4) Rules (generation + audit)
Each rule contains: required practice, insecure patterns, detection hints, and remediation.
JQ-SUPPLY-001: jQuery MUST be patched; do not run known vulnerable versions
Severity: Medium (High if internet-facing app AND version is known-vulnerable)
NOTE: 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.
Required:
- MUST NOT use jQuery versions with known high-impact vulnerabilities when a patched version exists.
- MUST upgrade past:
- CVE-2019-11358 (prototype pollution in jQuery before 3.4.0). ([NVD][13])
- CVE-2020-11022 / CVE-2020-11023 (XSS risks in DOM manipulation methods when handling untrusted HTML; patched in 3.5.0). ([NVD][1])
Insecure patterns:
- 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.). - Bundled vendor directories containing old minified jQuery without an upgrade path.
Detection hints:
- Search HTML/templates for
jquery-and parse version strings. - Check
package.json,package-lock.json,yarn.lock,pnpm-lock.yaml. - Check
vendor/,public/,static/,assets/,wwwroot/forjquery*.js.
Fix:
- Upgrade to current jQuery (prefer latest stable major; as of 2026-01-27, 4.0.0 is current). ([blog.jquery.com][7])
- 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).
Notes:
- If a product requirement forces old versions, report as “accepted risk requiring compensating controls”.
---
JQ-SUPPLY-002: Third-party script loading SHOULD use integrity and trusted origins
Severity: High
Required:
- MUST load jQuery and plugins only from trusted origins.
- If loaded from CDN, SHOULD use SRI (
integrity) and correctcrossoriginhandling. ([jquery.com][8])
Insecure patterns:
<script src="https://…/jquery.min.js"></script>with nointegrity.- Loading jQuery from random third-party CDNs without an explicit trust decision.
Detection hints:
- Scan HTML for
<script src=and check forintegrity=+crossorigin=. - Identify dynamic script insertion with untrusted URLs (see JQ-EXEC-001).
Fix:
- Prefer bundling via npm + lockfile.
- If using CDN, copy official script tag (jQuery CDN supports SRI). ([jquery.com][8])
Note: 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.
---
JQ-XSS-001: Untrusted data MUST NOT be inserted as HTML via jQuery DOM-manipulation methods
Severity: High (if attacker-controlled content reaches these sinks)
Required:
- MUST treat any HTML string insertion as a code execution boundary.
- MUST use safe alternatives for untrusted text:
.text(untrusted)(text, not HTML). ([jQuery API][14]).val(untrusted)for form fields. ([jQuery API][15])- Create elements and set text/attributes safely instead of concatenating HTML strings.
Insecure patterns (examples):
$(selector).html(untrusted)$(selector).append(untrusted)$(selector).before(untrusted)/.after(untrusted)/.replaceWith(untrusted)/.wrap(untrusted)(and similar)- Building markup:
"<div>" + untrusted + "</div>"then passing to jQuery
Detection hints:
- Grep for:
.html(,.append(,.prepend(,.before(,.after(,.replaceWith(,.wrap(,.wrapAll(,.wrapInner( - Trace dataflow into these calls from sources in §2.1.
Fix:
- Replace with
.text()/.val()or node construction:
const $el = $("<span>").text(untrusted); container.append($el);- If the output must contain limited markup, see JQ-XSS-002 (sanitization).
Notes:
- 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])
---
JQ-XSS-002: If rendering user-controlled HTML is required, it MUST be sanitized with a proven HTML sanitizer
Severity: Medium (High if rich HTML is attacker-controlled and sanitizer is weak/misconfigured)
Required:
- MUST NOT “roll your own” HTML sanitizer with regexes.
- If user-controlled HTML must be displayed (e.g., rich text comments), MUST sanitize using a well-maintained HTML sanitizer and a restrictive allowlist.
- DOMPurify is a common choice; use conservative configuration and keep it updated. ([GitHub][17])
- Where available, MAY consider the browser HTML Sanitizer API (note: limited browser availability). ([MDN Web Docs][18])
- SHOULD pair sanitization with CSP and, where feasible, Trusted Types for defense in depth. ([OWASP Cheat Sheet Series][9])
Insecure patterns:
- Regex-based “strip
<script>” or “escape<” attempts followed by.html()insertion. - DOMPurify (or similar) configured to allow overly broad tags/attributes, or configuration that’s not reviewed.
Detection hints:
- Search for “sanitize” helper functions, regex replacing
</>patterns, or “allow all tags” configs. - Identify features that render user-generated “rich text” or “custom HTML”.
- Check if sanitizer results are inserted with
.html()or equivalent sinks.
Fix:
- Introduce a sanitizer with strict allowlist.
- Centralize the “sanitize then inject” pattern into a single reviewed module.
- Add regression tests covering representative malicious inputs (don’t store payloads in logs or telemetry).
False positive notes:
- If content is guaranteed trusted (e.g., compiled templates shipped by you), document the trust boundary and why it is not attacker-controlled.
---
JQ-XSS-003: $(untrustedString) and jQuery.parseHTML MUST NOT process attacker-controlled markup
Severity: High (if attacker-controlled)
Required:
- MUST NOT pass attacker-controlled strings to
$()when they might be interpreted as HTML. - MUST treat
jQuery.parseHTML(html, …, keepScripts)as a high-risk primitive; keepScripts MUST befalsefor any untrusted input. ([jQuery API][2])
Insecure patterns:
const $node = $(untrusted);$.parseHTML(untrusted, /* context */, true)(scripts preserved)
Detection hints:
- Search for
$(calls where the argument is not a static selector or static markup. - Search for
$.parseHTML(and inspect thekeepScriptsargument.
Fix:
- Use DOM creation with constant tag names and
.text()for untrusted values. - If parsing HTML is necessary, sanitize first (JQ-XSS-002) and keep scripts disabled.
---
JQ-XSS-004: .load() MUST be treated as an HTML+script injection surface
Severity: Medium (High if URL/content is attacker-controlled)
Required:
- MUST NOT use
.load()with attacker-controlled URLs or attacker-controlled HTML fragments. - MUST understand jQuery
.load()script behavior:
- Without a selector in the URL, content is passed to
.html()before scripts are removed, which can execute scripts. ([jQuery API][3]) - SHOULD prefer
fetch()/XHR to retrieve data, then render with safe DOM creation or sanitize explicitly.
Insecure patterns:
$("#target").load(untrustedUrl)$("#target").load("/path?param=" + untrusted)
Detection hints:
- Search for
.load(across JS/TS files. - Identify whether a selector is appended to the URL (the behavior differs). ([jQuery API][3])
- Trace whether the URL can be influenced by user input.
Fix:
- Replace
.load()with:
fetch()to retrieve JSON, then render via.text()/ node construction, orfetch()to retrieve HTML, sanitize it, then inject.- If
.load()must remain, ensure the URL is constant or strictly allowlisted and the returned content is trusted.
---
JQ-EXEC-001: Dynamic script execution and script fetching MUST NOT be reachable from untrusted input
Severity: High
Required:
- MUST NOT fetch-and-execute scripts from untrusted or user-influenced URLs.
- MUST treat these as code execution primitives:
$.getScript(url)executes the fetched script in the global context. ([jQuery API][4])$.ajax({ dataType: "script" })and other script-typed requests that execute responses.- SHOULD remove these patterns unless there is a strong, reviewed justification.
Insecure patterns:
$.getScript(untrustedUrl)$.ajax({ url: untrustedUrl, dataType: "script" })- Dynamic
<script src=...>injection wheresrcis derived from untrusted input.
Detection hints:
- Search for
getScript(,dataType: "script",globalEval,eval,new Function. - Look for “plugin loader” or “theme loader” features that accept URLs.
Fix:
- Bundle scripts at build time.
- If runtime-loading is required, restrict to allowlisted, versioned, integrity-checked assets (and ideally still avoid runtime code loading).
---
JQ-AJAX-001: JSONP MUST be disabled unless the endpoint is fully trusted (and even then, avoid)
Severity: Medium (High if attacker can influence URL/endpoint)
Required:
- MUST NOT use JSONP for untrusted endpoints because it executes JavaScript responses.
- When using
$.ajax, MUST explicitly disable JSONP for non-fully-trusted targets; jQuery’s own docs recommend settingjsonp: false“for security reasons” if you don’t trust the target. ([jQuery API][5]) - SHOULD prefer CORS with JSON (
dataType: "json") and explicit origin allowlists server-side.
Insecure patterns:
dataType: "jsonp"- URLs containing
callback=?or patterns that trigger JSONP behavior. callback arguments are historically XSS vectors. $.get(untrustedUrl)without pinningdataTypeand disabling JSONP (risk depends on options and jQuery behavior)
Detection hints:
- Search for
jsonp,dataType: "jsonp",callback=?. - Search for cross-domain AJAX where the URL is not hard-coded or allowlisted.
Fix:
- Use JSON over HTTPS with CORS configured server-side.
- Set:
dataType: "json"jsonp: false(defense in depth when URL might be ambiguous) ([jQuery API][5])
---
JQ-AJAX-002: State-changing AJAX requests using cookie auth MUST be CSRF-protected
Severity: High
NOTE: This only matters when using cookie based auth. If the request use Authorization header, there is no CSRF potential.
Required:
- If authentication uses cookies, MUST protect state-changing requests (POST/PUT/PATCH/DELETE) against CSRF.
- SHOULD use server-verified CSRF tokens; for AJAX calls, tokens are commonly sent in a custom header. ([OWASP Cheat Sheet Series][19])
- MUST NOT treat “it’s an AJAX request” as CSRF protection by itself.
Insecure patterns:
$.post("/transfer", {...})or$.ajax({ method: "POST", ... })with cookie auth and no CSRF token/header.- “CSRF protection” that only checks for
X-Requested-With(defense-in-depth only, not primary).
Detection hints:
- Enumerate state-changing AJAX calls and locate whether they include CSRF tokens.
- Identify how the server expects CSRF validation (meta tag, cookie-to-header double submit, synchronizer token, etc.).
Fix:
- Add CSRF token inclusion in a centralized place, e.g.,
$.ajaxSetup({ headers: { "X-CSRF-Token": token } }), and ensure server verifies. - Follow OWASP CSRF guidance for token properties and validation. ([OWASP Cheat Sheet Series][19])
False positive notes:
- If auth is not cookie-based (e.g., Authorization header bearer token) CSRF risk is different; verify actual auth mechanism.
---
JQ-ATTR-001: Untrusted values MUST NOT be written into dangerous attributes without validation/allowlisting
Severity: Low (High for events like onclick)
Required:
- MUST validate/allowlist URLs written into
href,src,action, etc. - MUST block dangerous schemes;
javascript:URLs are discouraged because they can execute code. ([MDN Web Docs][6]) - MUST NOT set event-handler attributes (
onclick,onerror, etc.) from strings. - SHOULD avoid writing untrusted strings into
styleattributes; prefer toggling predefined CSS classes.
Insecure patterns:
$("a").attr("href", untrustedUrl)$("img").attr("src", untrustedUrl)$(el).attr("style", untrustedCss)$(el).attr("onclick", untrustedJs)
Detection hints:
- Search for
.attr("href",.attr("src",.attr("style",.prop("href",.prop("src". - Trace whether inputs come from URL params, server JSON, DOM, or storage.
Fix:
- Parse and validate URLs with
new URL(value, location.origin)and allowlist protocols (https:etc.) and hostnames when needed. - For navigation targets, prefer relative paths you construct rather than full URLs.
- Replace
stylestrings withaddClass/removeClassusing predefined class names.
---
JQ-SELECTOR-001: User-controlled selector fragments MUST be escaped with jQuery.escapeSelector
Severity: Medium (can become High if it enables wrong-element selection in security-relevant UI)
Required:
- 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]) - MUST NOT concatenate raw attacker-controlled strings into selector expressions.
Insecure patterns:
$("#" + untrustedId)$("[data-id='" + untrusted + "']")(especially without strict quoting/escaping)
Detection hints:
- Search for
"#" +,". " +, or template strings used inside$(selectors. - Look for “select by user-supplied id”.
Fix:
$("#" + $.escapeSelector(untrustedId))([jQuery API][20])- Prefer stable internal IDs over user-derived selectors.
Notes:
- 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.
---
JQ-PROTOTYPE-001: Do not deep-merge untrusted objects; prevent prototype pollution
Severity: Medium
Required:
- MUST NOT deep-merge (
$.extend(true, …)) attacker-controlled objects into application objects without filtering dangerous keys. - MUST ensure jQuery is >= 3.4.0 to avoid CVE-2019-11358 prototype pollution behavior. ([NVD][13])
Insecure patterns:
$.extend(true, target, untrustedObj)$.extend(true, {}, defaults, untrustedObj)where untrustedObj comes from URL/JSON/storage
Detection hints:
- Search for
$.extend(trueand inspect sources of merged objects. - Search for “merge options” / “apply config” patterns using untrusted JSON.
Fix:
- Prefer:
- Shallow merges with an allowlisted set of keys, or
- A safe merge helper that explicitly rejects
__proto__,prototype,constructor, and nested occurrences. - Keep jQuery patched.
---
JQ-CSP-001: CSP and Trusted Types SHOULD be used to make DOM XSS harder to introduce and exploit
Severity: Medium
Required:
- SHOULD deploy CSP as defense-in-depth against XSS. ([OWASP Cheat Sheet Series][9])
- If enabling Trusted Types (
require-trusted-types-for), MUST ensure DOM injection goes through Trusted Types policies. ([MDN Web Docs][11]) - When using jQuery 4, SHOULD take advantage of its Trusted Types support (TrustedHTML inputs). ([blog.jquery.com][7])
Insecure patterns:
- “Fixing” a jQuery feature by weakening CSP (
script-src 'unsafe-inline'/'unsafe-eval') without a compensating plan. - No CSP on applications that render user content or manipulate DOM heavily.
Detection hints:
- Look for CSP headers (server configs, framework middleware, meta tags).
- If not visible in repo, flag as “verify at edge/runtime”.
Fix:
- Add CSP incrementally; start by eliminating inline scripts and inline event handlers, then tighten
script-src. - Add Trusted Types where supported and feasible.
---
5) Practical scanning heuristics (how to “hunt”)
When actively scanning, use these high-signal patterns:
- jQuery version / sourcing:
jquery-*.jsinvendor/orstatic/package.jsondependencyjquerypinned to old versions- CDN script tags lacking
integrity/crossorigin([jquery.com][8]) - HTML injection sinks (DOM XSS):
.html(,.append(,.prepend(,.before(,.after(,.replaceWith(,.wrap($(where argument might be HTML / template strings$.parseHTML(especially withkeepScripts=true([jQuery API][2]).load((and whether selector is appended; script behavior differs) ([jQuery API][3])- Script execution / dynamic code:
$.getScript(,dataType: "script"([jQuery API][4])dataType: "jsonp"orjsonp:usage;callback=?patterns ([jQuery API][5])eval,new Function,setTimeout("…"),$.globalEval- Dangerous attribute writes:
.attr("href", …),.attr("src", …),.attr("style", …)- Any assignment of
javascript:-like schemes or suspicious URL construction ([MDN Web Docs][6]) - Selector construction:
$("#" + user)and similar; fix via$.escapeSelector([jQuery API][20])- Prototype pollution:
$.extend(true, …, userObj); ensure jQuery >= 3.4.0 and filter dangerous keys ([NVD][13])- CSRF posture for AJAX:
$.post(/$.ajax({ method: ... })with cookies and no CSRF token/header ([OWASP Cheat Sheet Series][19])- Defense-in-depth:
- Absence of CSP/security headers in configs (or not visible; require runtime verification) ([OWASP Cheat Sheet Series][12])
Always try to confirm:
- data origin (untrusted vs trusted)
- sink type (HTML insertion / script execution / attribute / selector / object merge)
- protective controls present (sanitizer, allowlists, CSP, Trusted Types, CSRF validation)
---
6) Sources (accessed 2026-01-27)
Primary jQuery project documentation and release notes:
- 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]) - Download jQuery (latest version info; CDN + SRI guidance):
https://jquery.com/download/. ([jquery.com][8]) - jQuery API:
.html():https://api.jquery.com/html/. ([jQuery API][21]) - jQuery API:
.text():https://api.jquery.com/text/. ([jQuery API][14]) - jQuery API:
.append():https://api.jquery.com/append/. ([jQuery API][22]) - jQuery API:
.load()(script execution behavior):https://api.jquery.com/load/. ([jQuery API][3]) - jQuery API:
jQuery.parseHTML(…, keepScripts):https://api.jquery.com/jQuery.parseHTML/. ([jQuery API][2]) - jQuery API:
$.ajax()(jsonp: falsesecurity note):https://api.jquery.com/jQuery.ajax/. ([jQuery API][5]) - jQuery API:
$.getScript()(executes script):https://api.jquery.com/jQuery.getScript/. ([jQuery API][4]) - jQuery API:
jQuery.escapeSelector():https://api.jquery.com/jQuery.escapeSelector/. ([jQuery API][20])
jQuery vulnerabilities / advisories:
- NVD CVE-2019-11358 (prototype pollution; jQuery < 3.4.0):
https://nvd.nist.gov/vuln/detail/CVE-2019-11358. ([NVD][13]) - 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]) - NVD CVE-2020-11023 (XSS risk involving
<option>; patched in 3.5.0):https://nvd.nist.gov/vuln/detail/CVE-2020-11023. ([NVD][23]) - 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])
OWASP Cheat Sheet Series (web app security foundations relevant to jQuery usage):
- XSS Prevention:
https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html. ([OWASP Cheat Sheet Series][24]) - DOM-based XSS Prevention:
https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html. ([OWASP Cheat Sheet Series][25]) - CSRF Prevention:
https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html. ([OWASP Cheat Sheet Series][19]) - HTTP Security Headers:
https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html. ([OWASP Cheat Sheet Series][12]) - Content Security Policy Cheat Sheet:
https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html. ([OWASP Cheat Sheet Series][9])
Browser/platform references (SRI, CSP, Trusted Types, and dangerous URL schemes):
- MDN: Subresource Integrity (SRI):
https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity. ([MDN Web Docs][26]) - W3C: SRI specification:
https://www.w3.org/TR/sri-2/. ([W3C][27]) - MDN: CSP guide:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP. ([MDN Web Docs][28]) - MDN:
require-trusted-types-fordirective:https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/require-trusted-types-for. ([MDN Web Docs][11]) - MDN: Trusted Types API:
https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API. ([MDN Web Docs][29]) - W3C: Trusted Types specification:
https://www.w3.org/TR/trusted-types/. ([W3C][10]) - MDN:
javascript:URL scheme warning:https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Schemes/javascript. ([MDN Web Docs][6]) - DOMPurify project documentation:
https://github.com/cure53/DOMPurify. ([GitHub][17])
[1]: https://nvd.nist.gov/vuln/detail/cve-2020-11022?utm_source=chatgpt.com "CVE-2020-11022 Detail - NVD" [2]: https://api.jquery.com/jQuery.parseHTML/?utm_source=chatgpt.com "jQuery.parseHTML()" [3]: https://api.jquery.com/load/?utm_source=chatgpt.com ".load() | jQuery API Documentation" [4]: https://api.jquery.com/jQuery.getScript/?utm_source=chatgpt.com "jQuery.getScript()" [5]: https://api.jquery.com/jQuery.ajax/?utm_source=chatgpt.com "jQuery.ajax()" [6]: https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Schemes/javascript?utm_source=chatgpt.com "javascript: URLs - URIs - MDN Web Docs" [7]: https://blog.jquery.com/2026/01/17/jquery-4-0-0/ "jQuery 4.0.0 | Official jQuery Blog" [8]: https://jquery.com/download/ "Download jQuery | jQuery" [9]: https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html?utm_source=chatgpt.com "Content Security Policy - OWASP Cheat Sheet Series" [10]: https://www.w3.org/TR/trusted-types/?utm_source=chatgpt.com "Trusted Types" [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" [12]: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html?utm_source=chatgpt.com "HTTP Security Response Headers Cheat Sheet" [13]: https://nvd.nist.gov/vuln/detail/cve-2019-11358?utm_source=chatgpt.com "CVE-2019-11358 Detail - NVD" [14]: https://api.jquery.com/text/?utm_source=chatgpt.com ".text() | jQuery API Documentation" [15]: https://api.jquery.com/val/?utm_source=chatgpt.com ".val() | jQuery API Documentation" [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" [17]: https://github.com/cure53/DOMPurify?utm_source=chatgpt.com "DOMPurify - a DOM-only, super-fast, uber-tolerant XSS ..." [18]: https://developer.mozilla.org/en-US/docs/Web/API/HTML_Sanitizer_API?utm_source=chatgpt.com "HTML Sanitizer API - MDN Web Docs" [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" [20]: https://api.jquery.com/jQuery.escapeSelector/?utm_source=chatgpt.com "jQuery.escapeSelector()" [21]: https://api.jquery.com/html/?utm_source=chatgpt.com ".html() | jQuery API Documentation" [22]: https://api.jquery.com/append/?utm_source=chatgpt.com ".append() | jQuery API Documentation" [23]: https://nvd.nist.gov/vuln/detail/cve-2020-11023?utm_source=chatgpt.com "CVE-2020-11023 Detail - NVD" [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" [25]: https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html?utm_source=chatgpt.com "DOM based XSS Prevention Cheat Sheet" [26]: https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity?utm_source=chatgpt.com "Subresource Integrity - Security - MDN Web Docs" [27]: https://www.w3.org/TR/sri-2/?utm_source=chatgpt.com "Subresource Integrity" [28]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP?utm_source=chatgpt.com "Content Security Policy (CSP) - HTTP - MDN Web Docs" [29]: https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API?utm_source=chatgpt.com "Trusted Types API - MDN Web Docs"