Skip to main content

Writing Security Policies and npm Audit Configuration

A security policy codifies how your React team handles vulnerabilities, versions, and dependency decisions. Without one, developers make inconsistent choices: one ignores a low-severity vulnerability, another upgrades unnecessarily, a third skips npm audit entirely. npm audit configuration files (.npmauditignore, .npmrc) and documented policies (SECURITY.md, contributing guidelines) enforce consistent standards across the team and communicate intent to reviewers and auditors.

What is a Security Policy and Why React Teams Need One

A security policy answers: What vulnerabilities block production? Which packages require exact versions? What's the remediation timeline (days to patch critical vs. weeks for low)? Who approves exceptions? Without answers, audit drift accumulates: low-severity vulnerabilities pile up, and no one knows if they're acceptable or forgotten.

For React applications, a security policy is especially important because your app serves users. A vulnerability in an authentication library or form validator is critical; one in a logging utility is lower risk. A policy lets teams make context-aware decisions and document them.

Core Elements of a React Security Policy

1. Vulnerability Severity Response Times

Define when issues must be patched:

  • Critical/High: Patch within 48 hours or remove the package.
  • Moderate: Patch within 2 weeks.
  • Low: Patch in normal maintenance cycles (quarterly).

This prevents scope creep (patching everything immediately) and neglect (ignoring all updates).

2. Version Pinning Baseline

Define how packages are versioned:

  • High-risk packages (auth, crypto, build tools): Exact versions only (e.g., "1.2.3").
  • Core libraries (React, Vue, Angular): Tilde pinning (e.g., "~18.2.0") for patch updates.
  • Utilities (lodash, date-fns): Caret pinning (e.g., "^4.17.0") for minor updates.

This prevents accidental breakage and makes dependencies predictable.

3. Dependency Approval Process

  • Direct dependencies must be reviewed and approved before adding to package.json.
  • Transitive dependencies are audited via npm audit; if unfixable, must be documented.

4. Audit Governance

  • npm audit runs on every push to CI/CD.
  • Critical/high vulnerabilities block merges.
  • Moderate vulnerabilities require a documented exception (with expiration date).

Creating an npm Audit Configuration File

npm 8.4.1+ supports .npmauditignore for explicitly ignoring vulnerabilities. Create it at your project root:

{
"meta": {
"generated-by": "React Security Team",
"generated-at": "2026-06-02",
"policy-version": "1.0"
},
"advisory": {
"1234567": {
"from": "express > body-parser",
"reason": "Maintenance release; not in use in our codebase (no direct parsing of untrusted input)",
"expires": "2026-09-01"
},
"1234568": {
"from": "webpack > glob",
"reason": "Dev dependency only; not shipped to production",
"expires": "2026-12-01"
}
}
}

Each entry requires:

  • Advisory ID: The CVE or npm advisory number.
  • From: The package path (transitive dependencies shown as "parent > child").
  • Reason: Why this vulnerability is acceptable in your context.
  • Expires: When this exception expires (forces re-evaluation).

Load this file in your npm audit workflow:

npm audit --auditignore=.npmauditignore --audit-level=high

Configuring npm via .npmrc

.npmrc is npm's configuration file. Use it to enforce security defaults:

# .npmrc at project root
# Audit on every install
audit=true

# Fail CI if moderate or higher vulnerabilities
audit-level=moderate

# Require HTTPS for registry
registry=https://registry.npmjs.org/
strict-ssl=true

# Lockfile integrity checks
verify-store-integrity=true

# Disable post-install scripts to prevent typosquat attacks
ignore-scripts=false # Set to true if you don't use any postinstall scripts

With this configuration, npm install runs audit automatically and fails if moderate or higher vulnerabilities exist. No team member can bypass it (short of modifying .npmrc, which you can protect via code review).

Writing a SECURITY.md Policy Document

Create a SECURITY.md file at your repo root. This communicates your policy to contributors, maintainers, and security researchers:

# Security Policy for React: From Zero to Hero

## Reporting Vulnerabilities

If you discover a security vulnerability, please email [email protected] instead of using the public issue tracker.

## Supported Versions

We provide security updates for:
- Latest major version (e.g., v2.x): ongoing support
- Previous major version (e.g., v1.x): 6 months of support
- Older versions: no support (upgrade required)

## npm Dependency Security Policy

### Severity and Response Times
- **Critical / High:** Patch within 48 hours or remove the package.
- **Moderate:** Patch within 2 weeks.
- **Low:** Patch in normal maintenance (quarterly).

### Version Pinning Requirements
- Authentication and cryptography libraries: exact versions (e.g., "1.2.3").
- React, React DOM: tilde pinning (e.g., "~18.2.0").
- Utilities: caret pinning (e.g., "^4.17.0").

### Approval Workflow
1. All new dependencies require approval in pull request review.
2. Maintainers run npm audit before merging.
3. Vulnerabilities are tracked in a security issue (private if critical).
4. Dependabot PRs auto-merge minor/patch updates; major versions require manual review.

### Audit Exemptions
Vulnerabilities are not patched if:
1. The vulnerability does not affect the code path (documented with advisory ID).
2. The affected package is development-only and not shipped to production.
3. Patching introduces a breaking change that requires major refactoring (temporary, with expiration).

All exemptions are documented in `.npmauditignore` with expiration dates.

## npm audit and CI/CD

Every push to main or a pull request triggers:
```bash
npm ci
npm audit --audit-level=high
npm run test
npm run build

If npm audit detects high or critical vulnerabilities, the build fails, and the PR cannot be merged.

Contact

For security questions, contact: [email protected]


## Integrating Policy into CI/CD

Add a workflow that enforces policy:

```yaml
# .github/workflows/security-policy.yml
name: Security Policy Check
on: [push, pull_request]
jobs:
policy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- name: Verify security policy
run: |
# Check that .npmauditignore is valid JSON
python3 -m json.tool .npmauditignore > /dev/null || exit 1

# Fail if any exemption is expired
current_date=$(date -d now '+%Y-%m-%d')
grep -o '"expires": "[^"]*"' .npmauditignore | cut -d'"' -f4 | while read expire; do
if [[ "$expire" < "$current_date" ]]; then
echo "Expired exemption found: $expire"
exit 1
fi
done

# Run audit with exemptions
npm ci
npm audit --audit-level=high --auditignore=.npmauditignore

This enforces that exemptions don't linger indefinitely.

Security Policy Maintenance

Review your policy quarterly or when:

  • New vulnerability types emerge (e.g., dependency confusion attacks → add private registry rules).
  • Your team grows (clarify approval process).
  • An audit or penetration test identifies gaps.

Update .npmauditignore to expire old exemptions and add new ones as needed.

Key Takeaways

  • A security policy defines severity response times, version pinning rules, and approval workflows for npm dependencies.
  • .npmauditignore documents vulnerability exemptions with expiration dates, enforcing re-evaluation.
  • .npmrc enforces npm configuration defaults (audit on install, HTTPS registry, integrity checks).
  • SECURITY.md communicates policy to contributors and security researchers.
  • CI/CD integration ensures policy is enforced on every build, with no human override.

Frequently Asked Questions

What if a team member disagrees with the policy?

Document the concern, discuss at a team meeting, and update the policy if warranted. Policy is evolving, not static. However, until changed, it applies to everyone.

Can I ignore a critical vulnerability temporarily?

Yes, but only with an expiration date (e.g., "2026-07-01"). Add it to .npmauditignore, document the reason, and set a calendar reminder to revisit. Never ignore a critical vulnerability indefinitely.

Should a security policy differ for dev vs. production dependencies?

Yes. Development dependencies (webpack, jest, eslint) have lower risk because they don't ship to users. A moderate vulnerability in a build tool is lower priority than a moderate vulnerability in an auth library. Your policy should reflect this distinction.

Who approves new dependencies?

Define it in the policy. Typically: a security team or senior developer reviews npm packages before adding to package.json. This prevents typosquats and risky packages from entering the codebase.

Further Reading