
Security Best Practices
- 220 installs
- 30.1k repo stars
- Updated August 4, 2026
- davila7/claude-code-templates
This is a copy of security-best-practices by openai - installs and ranking accrue to the original listing.
Apply secure coding, auth, secrets, and deployment guardrails while hardening an app before release or during security review of new endpoints and agent tools.
About
The security-best-practices skill steers Claude through established application security patterns for SaaS, APIs, and agent workflows. It helps teams catch unsafe defaults, tighten authentication and secrets handling, and satisfy review gates before shipping production-facing software.
- Covers common appsec pitfalls and safer defaults
- Guides auth, input validation, and secrets handling
- Supports pre-launch hardening checklists
- Applies across APIs, SaaS, and agent surfaces
- Pairs well with code review and compliance needs
Security Best Practices by the numbers
- 220 all-time installs (skills.sh)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/davila7/claude-code-templates --skill security-best-practicesAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 220 |
|---|---|
| repo stars | ★ 30.1k |
| Last updated | August 4, 2026 |
| Repository | davila7/claude-code-templates ↗ |
What it does
Apply secure coding, auth, secrets, and deployment guardrails while hardening an app before release or during security review of new endpoints and agent tools.
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 codex.
interface:
display_name: "Security Best Practices"
short_description: "Security reviews and secure-by-default guidance"
default_prompt: "Review this codebase for security best practices and suggest secure-by-default improvements."
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf of
any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don\'t include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
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"