Showing preview only (215K chars total). Download the full file or copy to clipboard to get everything.
Repository: helmetjs/helmet
Branch: main
Commit: 046124a89d24
Files: 104
Total size: 190.7 KB
Directory structure:
gitextract_6o9fnhsw/
├── .gitattributes
├── .github/
│ ├── dependabot.yml
│ └── workflows/
│ └── nodejs.yml
├── .gitignore
├── .prettierignore
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── SECURITY.md
├── build/
│ ├── build-package.ts
│ └── helpers.ts
├── eslint.config.js
├── index.ts
├── middlewares/
│ ├── content-security-policy/
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── index.ts
│ │ └── package-overrides.json
│ ├── cross-origin-embedder-policy/
│ │ └── index.ts
│ ├── cross-origin-opener-policy/
│ │ └── index.ts
│ ├── cross-origin-resource-policy/
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── index.ts
│ │ └── package-overrides.json
│ ├── origin-agent-cluster/
│ │ └── index.ts
│ ├── referrer-policy/
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── index.ts
│ │ └── package-overrides.json
│ ├── strict-transport-security/
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── index.ts
│ │ └── package-overrides.json
│ ├── x-content-type-options/
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── index.ts
│ │ └── package-overrides.json
│ ├── x-dns-prefetch-control/
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── index.ts
│ │ └── package-overrides.json
│ ├── x-download-options/
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── index.ts
│ │ └── package-overrides.json
│ ├── x-frame-options/
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── index.ts
│ │ └── package-overrides.json
│ ├── x-permitted-cross-domain-policies/
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── index.ts
│ │ └── package-overrides.json
│ ├── x-powered-by/
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── index.ts
│ │ └── package-overrides.json
│ └── x-xss-protection/
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── index.ts
│ └── package-overrides.json
├── package.json
├── test/
│ ├── content-security-policy.test.ts
│ ├── cross-origin-embedder-policy.test.ts
│ ├── cross-origin-opener-policy.test.ts
│ ├── cross-origin-resource-policy.test.ts
│ ├── helpers.ts
│ ├── index.test.ts
│ ├── origin-agent-cluster.test.ts
│ ├── project-setups/
│ │ ├── .gitignore
│ │ ├── javascript-commonjs/
│ │ │ ├── check.js
│ │ │ └── package.json
│ │ ├── javascript-commonjs-default-member/
│ │ │ ├── check.js
│ │ │ └── package.json
│ │ ├── javascript-esm/
│ │ │ ├── check.js
│ │ │ └── package.json
│ │ ├── typescript-commonjs/
│ │ │ ├── check.ts
│ │ │ ├── package.json
│ │ │ └── tsconfig.json
│ │ ├── typescript-commonjs-nodenext-moduleResolution/
│ │ │ ├── check.ts
│ │ │ ├── package.json
│ │ │ └── tsconfig.json
│ │ ├── typescript-esnext/
│ │ │ ├── check.ts
│ │ │ ├── package.json
│ │ │ └── tsconfig.json
│ │ ├── typescript-nodenext-commonjs/
│ │ │ ├── check.ts
│ │ │ ├── package.json
│ │ │ └── tsconfig.json
│ │ └── typescript-nodenext-esm/
│ │ ├── check.ts
│ │ ├── package.json
│ │ └── tsconfig.json
│ ├── project-setups.test.ts
│ ├── referrer-policy.test.ts
│ ├── source-files.test.ts
│ ├── strict-transport-security.test.ts
│ ├── x-content-type-options.test.ts
│ ├── x-dns-prefetch-control.test.ts
│ ├── x-download-options.test.ts
│ ├── x-frame-options.test.ts
│ ├── x-permitted-cross-domain-policies.test.ts
│ ├── x-powered-by.test.ts
│ └── x-xss-protection.test.ts
└── tsconfig.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
* text=auto eol=lf
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
================================================
FILE: .github/workflows/nodejs.yml
================================================
name: Node.js CI
on: [push]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x, 20.x, 22.x, 24.x]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: ${{ matrix.node-version }}
check-latest: true
- run: npm ci
- run: npm test
env:
CI: true
================================================
FILE: .gitignore
================================================
/node_modules/
/coverage/
.eslintcache
================================================
FILE: .prettierignore
================================================
/coverage/
================================================
FILE: CHANGELOG.md
================================================
# Changelog
## Unreleased
- `Cross-Origin-Opener-Policy`: support `noopener-allow-popups`. See [#522](https://github.com/helmetjs/helmet/pull/522)
- Improve error message when passing duplicate options
## 8.1.0 - 2025-03-17
### Changed
- `Content-Security-Policy` gives a better error when a directive value, like `self`, should be quoted. See [#482](https://github.com/helmetjs/helmet/issues/482)
## 8.0.0 - 2024-09-28
### Changed
- **Breaking:** `Strict-Transport-Security` now has a max-age of 365 days, up from 180
- **Breaking:** `Content-Security-Policy` middleware now throws an error if a directive should have quotes but does not, such as `self` instead of `'self'`. See [#454](https://github.com/helmetjs/helmet/issues/454)
- **Breaking:** `Content-Security-Policy`'s `getDefaultDirectives` now returns a deep copy. This only affects users who were mutating the result
- **Breaking:** `Strict-Transport-Security` now throws an error when "includeSubDomains" option is misspelled. This was previously a warning
### Removed
- **Breaking:** Drop support for Node 16 and 17. Node 18+ is now required
## 7.2.0 - 2024-09-28
### Changed
- `Content-Security-Policy` middleware now warns if a directive should have quotes but does not, such as `self` instead of `'self'`. This will be an error in future versions. See [#454](https://github.com/helmetjs/helmet/issues/454)
## 7.1.0 - 2023-11-07
### Added
- `helmet.crossOriginEmbedderPolicy` now supports the `unsafe-none` directive. See [#447](https://github.com/helmetjs/helmet/pull/447)
## 7.0.0 - 2023-05-06
### Changed
- **Breaking:** `Cross-Origin-Embedder-Policy` middleware is now disabled by default. See [#411](https://github.com/helmetjs/helmet/issues/411)
### Removed
- **Breaking:** Drop support for Node 14 and 15. Node 16+ is now required
- **Breaking:** `Expect-CT` is no longer part of Helmet. If you still need it, you can use the [`expect-ct` package](https://www.npmjs.com/package/expect-ct). See [#378](https://github.com/helmetjs/helmet/issues/378)
## 6.2.0 - 2023-05-06
- Expose header names (e.g., `strictTransportSecurity` for the `Strict-Transport-Security` header, instead of `hsts`)
- Rework documentation
## 6.1.5 - 2023-04-11
### Fixed
- Fixed yet another issue with TypeScript exports. See [#420](https://github.com/helmetjs/helmet/pull/420)
## 6.1.4 - 2023-04-10
### Fixed
- Fix another issue with TypeScript default exports. See [#418](https://github.com/helmetjs/helmet/pull/418)
## 6.1.3 - 2023-04-10
### Fixed
- Fix issue with TypeScript default exports. See [#417](https://github.com/helmetjs/helmet/pull/417)
## 6.1.2 - 2023-04-09
### Fixed
- Retored `main` to package to help with some build tools
## 6.1.1 - 2023-04-08
### Fixed
- Fixed missing package metadata
## 6.1.0 - 2023-04-08
### Changed
- Improve support for various TypeScript setups, including "nodenext". See [#405](https://github.com/helmetjs/helmet/pull/405)
## 6.0.1 - 2022-11-29
### Fixed
- `crossOriginEmbedderPolicy` did not accept options at the top level. See [#390](https://github.com/helmetjs/helmet/issues/390)
## 6.0.0 - 2022-08-26
### Changed
- **Breaking:** `helmet.contentSecurityPolicy` no longer sets `block-all-mixed-content` directive by default
- **Breaking:** `helmet.expectCt` is no longer set by default. It can, however, be explicitly enabled. It will be removed in Helmet 7. See [#310](https://github.com/helmetjs/helmet/issues/310)
- **Breaking:** Increase TypeScript strictness around some arguments. Only affects TypeScript users, and may not require any code changes. See [#369](https://github.com/helmetjs/helmet/issues/369)
- `helmet.frameguard` no longer offers a specific error when trying to use `ALLOW-FROM`; it just says that it is unsupported. Only the error message has changed
### Removed
- **Breaking:** Dropped support for Node 12 and 13. Node 14+ is now required
## 5.1.1 - 2022-07-23
### Changed
- Fix TypeScript bug with some TypeScript configurations. See [#375](https://github.com/helmetjs/helmet/pull/375) and [#359](https://github.com/helmetjs/helmet/issues/359)
## 5.1.0 - 2022-05-17
### Added
- `Cross-Origin-Embedder-Policy`: support `credentialless` policy. See [#365](https://github.com/helmetjs/helmet/pull/365)
- Documented how to set both `Content-Security-Policy` and `Content-Security-Policy-Report-Only`
### Changed
- Cleaned up some documentation around `Origin-Agent-Cluster`
## 5.0.2 - 2022-01-22
### Changed
- Improve imports for CommonJS and ECMAScript modules. See [#345](https://github.com/helmetjs/helmet/pull/345)
- Fixed some documentation
## 5.0.1 - 2022-01-03
### Changed
- Fixed some documentation
### Removed
- Removed some unused internal code
## 5.0.0 - 2022-01-02
### Added
- ECMAScript module imports (i.e., `import helmet from "helmet"` and `import { frameguard } from "helmet"`). See [#320](https://github.com/helmetjs/helmet/issues/320)
### Changed
- **Breaking:** `helmet.contentSecurityPolicy`: `useDefaults` option now defaults to `true`
- **Breaking:** `helmet.contentSecurityPolicy`: `form-action` directive is now set to `'self'` by default
- **Breaking:** `helmet.crossOriginEmbedderPolicy` is enabled by default
- **Breaking:** `helmet.crossOriginOpenerPolicy` is enabled by default
- **Breaking:** `helmet.crossOriginResourcePolicy` is enabled by default
- **Breaking:** `helmet.originAgentCluster` is enabled by default
- `helmet.frameguard`: add TypeScript editor autocomplete. See [#322](https://github.com/helmetjs/helmet/pull/322)
- Top-level `helmet()` function is slightly faster
### Removed
- **Breaking:** Drop support for Node 10 and 11. Node 12+ is now required
## 4.6.0 - 2021-05-01
### Added
- `helmet.contentSecurityPolicy`: the `useDefaults` option, defaulting to `false`, lets you selectively override defaults more easily
- Explicitly define TypeScript types in `package.json`. See [#303](https://github.com/helmetjs/helmet/pull/303)
## 4.5.0 - 2021-04-17
### Added
- `helmet.crossOriginEmbedderPolicy`: a new middleware for the `Cross-Origin-Embedder-Policy` header, disabled by default
- `helmet.crossOriginOpenerPolicy`: a new middleware for the `Cross-Origin-Opener-Policy` header, disabled by default
- `helmet.crossOriginResourcePolicy`: a new middleware for the `Cross-Origin-Resource-Policy` header, disabled by default
### Changed
- `true` enables a middleware with default options. Previously, this would fail with an error if the middleware was already enabled by default.
- Log a warning when passing options to `originAgentCluster` at the top level
### Fixed
- Incorrect documentation
## 4.4.1 - 2021-01-18
### Changed
- Shrink the published package by about 2.5 kB
## 4.4.0 - 2021-01-17
### Added
- `helmet.originAgentCluster`: a new middleware for the `Origin-Agent-Cluster` header, disabled by default
## 4.3.1 - 2020-12-27
### Fixed
- `helmet.contentSecurityPolicy`: broken TypeScript types. See [#283](https://github.com/helmetjs/helmet/issues/283)
## 4.3.0 - 2020-12-27
### Added
- `helmet.contentSecurityPolicy`: setting the `default-src` to `helmet.contentSecurityPolicy.dangerouslyDisableDefaultSrc` disables it
### Changed
- `helmet.frameguard`: slightly improved error messages for non-strings
## 4.2.0 - 2020-11-01
### Added
- `helmet.contentSecurityPolicy`: get the default directives with `contentSecurityPolicy.getDefaultDirectives()`
### Changed
- `helmet()` now supports objects that don't have `Object.prototype` in their chain, such as `Object.create(null)`, as options
- `helmet.expectCt`: `max-age` is now first. See [#264](https://github.com/helmetjs/helmet/pull/264)
## 4.1.1 - 2020-09-10
### Changed
- Fixed a few errors in the README
## 4.1.0 - 2020-08-15
### Added
- `helmet.contentSecurityPolicy`:
- Directive values can now include functions, as they could in Helmet 3. See [#243](https://github.com/helmetjs/helmet/issues/243)
### Changed
- Helmet should now play more nicely with TypeScript
### Removed
- The `HelmetOptions` interface is no longer exported. This only affects TypeScript users. If you need the functionality back, see [this comment](https://github.com/helmetjs/helmet/issues/235#issuecomment-674016883)
## 4.0.0 - 2020-08-02
See the [Helmet 4 upgrade guide](https://github.com/helmetjs/helmet/wiki/Helmet-4-upgrade-guide) for help upgrading from Helmet 3.
### Added
- `helmet.contentSecurityPolicy`:
- If no `default-src` directive is supplied, an error is thrown
- Directive lists can be any iterable, not just arrays
### Changed
- This package no longer has dependencies. This should have no effect on end users, other than speeding up installation time.
- `helmet.contentSecurityPolicy`:
- There is now a default set of directives if none are supplied
- Duplicate keys now throw an error. See [helmetjs/csp#73](https://github.com/helmetjs/csp/issues/73)
- This middleware is more lenient, allowing more directive names or values
- `helmet.xssFilter` now disables the buggy XSS filter by default. See [#230](https://github.com/helmetjs/helmet/issues/230)
### Removed
- Dropped support for old Node versions. Node 10+ is now required
- `helmet.featurePolicy`. If you still need it, use the `feature-policy` package on npm.
- `helmet.hpkp`. If you still need it, use the `hpkp` package on npm.
- `helmet.noCache`. If you still need it, use the `nocache` package on npm.
- `helmet.contentSecurityPolicy`:
- Removed browser sniffing (including the `browserSniff` and `disableAndroid` parameters). See [helmetjs/csp#97](https://github.com/helmetjs/csp/issues/97)
- Removed conditional support. This includes directive functions and support for a function as the `reportOnly`. [Read this if you need help.](https://github.com/helmetjs/helmet/wiki/Conditionally-using-middleware)
- Removed a lot of checks—you should be checking your CSP with a different tool
- Removed support for legacy headers (and therefore the `setAllHeaders` parameter). [Read this if you need help.](https://github.com/helmetjs/helmet/wiki/Setting-legacy-Content-Security-Policy-headers-in-Helmet-4)
- Removed the `loose` option
- Removed support for functions as directive values. You must supply an iterable of strings
- `helmet.frameguard`:
- Dropped support for the `ALLOW-FROM` action. [Read more here.](https://github.com/helmetjs/helmet/wiki/How-to-use-X%E2%80%93Frame%E2%80%93Options's-%60ALLOW%E2%80%93FROM%60-directive)
- `helmet.hidePoweredBy` no longer accepts arguments. See [this article](https://github.com/helmetjs/helmet/wiki/How-to-set-a-custom-X%E2%80%93Powered%E2%80%93By-header) to see how to replicate the removed behavior. See [#224](https://github.com/helmetjs/helmet/issues/224).
- `helmet.hsts`:
- Dropped support for `includeSubdomains` with a lowercase D. See [#231](https://github.com/helmetjs/helmet/issues/231)
- Dropped support for `setIf`. [Read this if you need help.](https://github.com/helmetjs/helmet/wiki/Conditionally-using-middleware) See [#232](https://github.com/helmetjs/helmet/issues/232)
- `helmet.xssFilter` no longer accepts options. Read ["How to disable blocking with X-XSS-Protection"](https://github.com/helmetjs/helmet/wiki/How-to-disable-blocking-with-X%E2%80%93XSS%E2%80%93Protection) and ["How to enable the `report` directive with X-XSS-Protection"](https://github.com/helmetjs/helmet/wiki/How-to-enable-the-%60report%60-directive-with-X%E2%80%93XSS%E2%80%93Protection) if you need the legacy behavior.
## 3.23.3 - 2020-06-26
### Changed
- `helmet.expectCt` is no longer a separate package. This should have no effect on end users.
- `helmet.frameguard` is no longer a separate package. This should have no effect on end users.
## 3.23.2 - 2020-06-23
### Changed
- `helmet.dnsPrefetchControl` is no longer a separate package. This should have no effect on end users.
## 3.23.1 - 2020-06-16
### Changed
- `helmet.ieNoOpen` is no longer a separate package. This should have no effect on end users.
## 3.23.0 - 2020-06-12
### Deprecated
- `helmet.featurePolicy` is deprecated. Use the `feature-policy` module instead.
## 3.22.1 - 2020-06-10
### Changed
- Rewrote internals in TypeScript. This should have no effect on end users.
## 3.22.0 - 2020-03-24
### Changed
- Updated `helmet-csp` to v2.10.0
- Add support for the `allow-downloads` sandbox directive. See [helmet-csp#103](https://github.com/helmetjs/csp/pull/103)
### Deprecated
- `helmet.noCache` is deprecated. Use the `nocache` module instead. See [#215](https://github.com/helmetjs/helmet/issues/215)
## 3.21.3 - 2020-02-24
### Changed
- Updated `helmet-csp` to v2.9.5
- Updated `bowser` subdependency from 2.7.0 to 2.9.0
- Fixed an issue some people were having when importing the `bowser` subdependency. See [helmet-csp#96](https://github.com/helmetjs/csp/issues/96) and [#101](https://github.com/helmetjs/csp/pull/101)
## 3.21.2 - 2019-10-21
### Changed
- Updated `helmet-csp` to v2.9.4
- Updated `bowser` subdependency from 2.6.1 to 2.7.0. See [helmet-csp#94](https://github.com/helmetjs/csp/pull/94)
## 3.21.1 - 2019-09-20
### Fixed
- Updated `helmet-csp` to v2.9.2
- Fixed a bug where a request from Firefox 4 could delete `default-src` from future responses
- Fixed tablet PC detection by updating `bowser` subdependency to latest version
## 3.21.0 - 2019-09-04
### Added
- Updated `x-xss-protection` to v1.3.0
- Added `mode: null` to disable `mode=block`
### Changed
- Updated `helmet-csp` to v2.9.1
- Updated `bowser` subdependency from 2.5.3 to 2.5.4. See [helmet-csp#88](https://github.com/helmetjs/csp/pull/88)
## 3.20.1 - 2019-08-28
### Changed
- Updated `helmet-csp` to v2.9.0
## 3.20.0 - 2019-07-24
### Changed
- Updated `helmet-csp` to v2.8.0
## 3.19.0 - 2019-07-17
### Changed
- Updated `dns-prefetch-control` to v0.2.0
- Updated `dont-sniff-mimetype` to v1.1.0
- Updated `helmet-crossdomain` to v0.4.0
- Updated `hide-powered-by` to v1.1.0
- Updated `x-xss-protection` to v1.2.0
## 3.18.0 - 2019-05-05
### Added
- `featurePolicy` has 19 new features: `ambientLightSensor`, `documentDomain`, `documentWrite`, `encryptedMedia`, `fontDisplayLateSwap`, `layoutAnimations`, `legacyImageFormats`, `loadingFrameDefaultEager`, `oversizedImages`, `pictureInPicture`, `serial`, `syncScript`, `unoptimizedImages`, `unoptimizedLosslessImages`, `unoptimizedLossyImages`, `unsizedMedia`, `verticalScroll`, `wakeLock`, and `xr`
### Changed
- Updated `expect-ct` to v0.2.0
- Updated `feature-policy` to v0.3.0
- Updated `frameguard` to v3.1.0
- Updated `nocache` to v2.1.0
## 3.17.0 - 2019-05-03
### Added
- `referrerPolicy` now supports multiple values
### Changed
- Updated `referrerPolicy` to v1.2.0
## 3.16.0 - 2019-03-10
### Added
- Add email to `bugs` field in `package.json`
### Changed
- Updated `hsts` to v2.2.0
- Updated `ienoopen` to v1.1.0
- Changelog is now in the [Keep A Changelog](https://keepachangelog.com/) format
- Dropped support for Node <4. See [the commit](https://github.com/helmetjs/helmet/commit/a49cec3ca58cce484d2d05e1f908549caa92ed03) for more information
- Updated Adam Baldwin's contact information
### Deprecated
- `helmet.hsts`'s `setIf` option has been deprecated and will be removed in `hsts@3`. See [helmetjs/hsts#22](https://github.com/helmetjs/hsts/issues/22) for more
* The `includeSubdomains` option (with a lowercase `d`) has been deprecated and will be removed in `hsts@3`. Use the uppercase-D `includeSubDomains` option instead. See [helmetjs/hsts#21](https://github.com/helmetjs/hsts/issues/21) for more
## 3.15.1 - 2019-02-10
### Deprecated
- The `hpkp` middleware has been deprecated. If you still need to use this module, install the standalone `hpkp` module from npm. See [#180](https://github.com/helmetjs/helmet/issues/180) for more.
## 3.15.0 - 2018-11-07
### Added
- `helmet.featurePolicy` now supports four new features
## 3.14.0 - 2018-10-09
### Added
- `helmet.featurePolicy` middleware
## 3.13.0 - 2018-07-22
### Added
- `helmet.permittedCrossDomainPolicies` middleware
## 3.12.2 - 2018-07-20
### Fixed
- Removed `lodash.reduce` dependency from `csp`
## 3.12.1 - 2018-05-16
### Fixed
- `expectCt` should use comma instead of semicolon as delimiter
## 3.12.0 - 2018-03-02
### Added
- `xssFilter` now supports `reportUri` option
## 3.11.0 - 2018-02-09
### Added
- Main Helmet middleware is now named to help with debugging
## 3.10.0 - 2018-01-23
### Added
- `csp` now supports `prefix-src` directive
### Fixed
- `csp` no longer loads JSON files internally, helping some module bundlers
- `false` should be able to disable a CSP directive
## 3.9.0 - 2017-10-13
### Added
- `csp` now supports `strict-dynamic` value
- `csp` now supports `require-sri-for` directive
### Changed
- Removed `connect` dependency
## 3.8.2 - 2017-09-27
### Changed
- Updated `connect` dependency to latest
## 3.8.1 - 2017-07-28
### Fixed
- `csp` does not automatically set `report-to` when setting `report-uri`
## 3.8.0 - 2017-07-21
### Changed
- `hsts` no longer cares whether it's HTTPS and always sets the header
## 3.7.0 - 2017-07-21
### Added
- `csp` now supports `report-to` directive
### Changed
- Throw an error when used incorrectly
- Add a few documentation files to `npmignore`
## 3.6.1 - 2017-05-21
### Changed
- Bump `connect` version
## 3.6.0 - 2017-05-04
### Added
- `expectCt` middleware for setting the `Expect-CT` header
## 3.5.0 - 2017-03-06
### Added
- `csp` now supports the `worker-src` directive
## 3.4.1 - 2017-02-24
### Changed
- Bump `connect` version
## 3.4.0 - 2017-01-13
### Added
- `csp` now supports more `sandbox` directives
## 3.3.0 - 2016-12-31
### Added
- `referrerPolicy` allows `strict-origin` and `strict-origin-when-cross-origin` directives
### Changed
- Bump `connect` version
## 3.2.0 - 2016-12-22
### Added
- `csp` now allows `manifest-src` directive
## 3.1.0 - 2016-11-03
### Added
- `csp` now allows `frame-src` directive
## 3.0.0 - 2016-10-28
### Changed
- `csp` will check your directives for common mistakes and throw errors if it finds them. This can be disabled with `loose: true`.
- Empty arrays are no longer allowed in `csp`. For source lists (like `script-src` or `object-src`), use the standard `scriptSrc: ["'none'"]`. The `sandbox` directive can be `sandbox: true` to block everything.
- `false` can disable a CSP directive. For example, `scriptSrc: false` is the same as not specifying it.
- In CSP, `reportOnly: true` no longer requires a `report-uri` to be set.
- `hsts`'s `maxAge` now defaults to 180 days (instead of 1 day)
- `hsts`'s `maxAge` parameter is seconds, not milliseconds
- `hsts` includes subdomains by default
- `domain` parameter in `frameguard` cannot be empty
### Removed
- `noEtag` option no longer present in `noCache`
- iOS Chrome `connect-src` workaround in CSP module
## 2.3.0 - 2016-09-30
### Added
- `hpkp` middleware now supports the `includeSubDomains` property with a capital D
### Fixed
- `hpkp` was setting `includeSubdomains` instead of `includeSubDomains`
## 2.2.0 - 2016-09-16
### Added
- `referrerPolicy` middleware
## 2.1.3 - 2016-09-07
### Changed
- Top-level aliases (like `helmet.xssFilter`) are no longer dynamically required
## 2.1.2 - 2016-07-27
### Deprecated
- `nocache`'s `noEtag` option is now deprecated
### Fixed
- `csp` now better handles Firefox on mobile
## 2.1.1 - 2016-06-10
### Changed
- Remove several dependencies from `helmet-csp`
### Fixed
- `frameguard` had a documentation error about its default value
- `frameguard` docs in main Helmet readme said `frameguard`, not `helmet.frameguard`
## 2.1.0 - 2016-05-18
### Added
- `csp` lets you dynamically set `reportOnly`
## 2.0.0 - 2016-04-29
### Added
- Pass configuration to enable/disable default middlewares
### Changed
- `dnsPrefetchControl` middleware is now enabled by default
### Removed
- No more module aliases. There is now just one way to include each middleware
- `frameguard` can no longer be initialized with strings; you must use an object
### Fixed
- Make `hpkp` lowercase in documentation
- Update `hpkp` spec URL in readmes
- Update `frameguard` header name in readme
## 1.3.0 - 2016-03-01
### Added
- `hpkp` has a `setIf` option to conditionally set the header
## 1.2.0 - 2016-02-29
### Added
- `csp` now has a `browserSniff` option to disable all user-agent sniffing
### Changed
- `frameguard` can now be initialized with options
- Add `npmignore` file to speed up installs slightly
## 1.1.0 - 2016-01-12
### Added
- Code of conduct
- `dnsPrefetchControl` middleware
### Fixed
- `csp` readme had syntax errors
## 1.0.2 - 2016-01-08
### Fixed
- `csp` wouldn't recognize `IE Mobile` browsers
- `csp` had some errors in its readme
- Main readme had a syntax error
## 1.0.1 - 2015-12-19
### Fixed
- `csp` with no User Agent would cause errors
## 1.0.0 - 2015-12-18
### Added
- `csp` module supports dynamically-generated values
### Changed
- `csp` directives are now under the `directives` key
- `hpkp`'s `Report-Only` header is now opt-in, not opt-out
- Tweak readmes of every sub-repo
### Removed
- `crossdomain` middleware
- `csp` no longer throws errors when some directives aren't quoted (`'self'`, for example)
- `maxage` option in the `hpkp` middleware
- `safari5` option from `csp` module
### Fixed
- Old Firefox Content-Security-Policy behavior for `unsafe-inline` and `unsafe-eval`
- Dynamic `csp` policies is no longer recursive
## 0.15.0 - 2015-11-26
### Changed
- `hpkp` allows a `report-uri` without the `Report-Only` header
## 0.14.0 - 2015-11-01
### Added
- `nocache` now sends the `Surrogate-Control` header
### Changed
- `nocache` no longer contains the `private` directive in the `Cache-Control` header
## 0.13.0 - 2015-10-23
### Added
- `xssFilter` now has a function name
- Added new CSP docs to readme
### Changed
- HSTS option renamed from `includeSubdomains` to `includeSubDomains`
## 0.11.0 - 2015-09-18
### Added
- `csp` now supports Microsoft Edge
- CSP Level 2 support
### Changed
- Updated `connect` to 3.4.0
- Updated `depd` to 1.1.0
### Fixed
- Added `license` key to `csp`'s `package.json`
- Empty `csp` directives now support every directive, not just `sandbox`
## 0.10.0 - 2015-07-08
### Added
- Add "Handling CSP violations" to `csp` readme
- Add license to `package.json`
### Changed
- `hpkp` had a link to the wrong place in its readme
- `hpkp` requires 2 or more pins
### Fixed
- `hpkp` might have miscalculated `maxAge` slightly wrong
## 0.9.0 - 2015-04-24
### Changed
- `nocache` adds `private` to its `Cache-Control` directive
- Added a description to `package.json`
## 0.8.0 - 2015-04-21
### Changed
- Removed hefty Lodash dependency from HSTS and CSP
- Updated string detection module in Frameguard
- Changed readme slightly to better reflect project's focus
### Deprecated
- Deprecated `crossdomain` middleware
### Removed
- `crossdomain` is no longer a default middleware
## 0.7.1 - 2015-03-23
### Changed
- Updated all outdated dependencies (insofar as possible)
- HSTS now uses Lodash like all the rest of the libraries
## 0.7.0 - 2015-03-05
### Added
- `hpkp` middleware
### Changed
- Travis CI should test 0.10 and 0.12
- Minor code cleanup
## 0.6.2 - 2015-03-01
### Changed
- Improved `xssFilter` performance
- Updated Lodash versions
## 0.6.1 - 2015-02-13
### Added
- "Other recommended modules" in README
### Changed
- Updated Lodash version
### Fixed
- `frameguard` middleware exported a function called `xframe`
## 0.6.0 - 2015-01-21
### Added
- You can disable `csp` for Android
### Fixed
- `csp` on Chrome Mobile on Android and iOS
## 0.5.4 - 2014-12-21
### Changed
- `nocache` should force revalidation
## 0.5.3 - 2014-12-08
### Changed
- `platform` version in CSP and X-XSS-Protection
### Fixed
- Updated bad wording in frameguard docs
## 0.5.2 - 2014-11-16
### Changed
- Updated Connect version
### Fixed
- Fixed minor `csp` bugfixes
## 0.5.1 - 2014-11-09
### Changed
- Updated URLs in `package.json` for new URL
### Fixed
- CSP would set all headers forever after receiving an unknown user agent
## 0.5.0 - 2014-10-28
### Added
- Most middlewares have some aliases now
### Changed
- `xframe` now called `frameguard` (though `xframe` still works)
- `frameguard` chooses sameorigin by default
- `frameguard` understands "SAME-ORIGIN" in addition to "SAMEORIGIN"
- `nocache` removed from default middleware stack
- Middleware split out into their own modules
- Documentation
- Updated supported Node version to at least 0.10.0
- Bumped Connect version
### Removed
- Deprecation warnings
### Fixed
- Readme link was broken
## 0.4.2 - 2014-10-16
### Added
- Support preload in HSTS header
## 0.4.1 - 2014-08-24
### Added
- Use [helmet-crossdomain](https://github.com/helmetjs/crossdomain) to test the waters
- 2 spaces instead of 4 throughout the code
## 0.4.0 - 2014-07-17
### Added
- `nocache` now sets the Expires and Pragma headers
- `nocache` now allows you to crush ETags
### Changed
- Improved the docs for nosniff
- Reverted HSTS behavior of requiring a specified max-age
### Fixed
- Allow HSTS to have a max-age of 0
## 0.3.2 - 2014-06-30
### Added
- All middleware functions are named
- Throw error with non-positive HSTS max-age
### Changed
- Added semicolons in README
- Make some Errors more specific
### Removed
- Removed all comment headers; refer to the readme
### Fixed
- `helmet()` was having issues
- Fixed Syntax errors in README
This changelog was created after the release of 0.3.1.
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our community include:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
- Focusing on what is best not just for us as individuals, but for the overall community
Examples of unacceptable behavior include:
- The use of sexualized language or imagery, and sexual attention or advances of any kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email address, without their explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at [evanhahn.com/contact](https://evanhahn.com/contact). All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of actions.
**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at <https://www.contributor-covenant.org/faq>. Translations are available at <https://www.contributor-covenant.org/translations>.
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Helmet
Helmet welcomes contributors! This guide should help you submit issues and pull requests.
## Got a question, problem, or feature request?
The documentation and [Stack Overflow](https://stackoverflow.com/questions/tagged/helmet.js) are good places to start.
Feel free to [add an issue](https://github.com/helmetjs/helmet/issues) or [contact the maintainer](https://evanhahn.com/contact) if those don't help!
## Want to submit a change?
If you're not sure whether your change will be welcomed, [add an issue](https://github.com/helmetjs/helmet/issues) to ask.
Once you're ready to make your change, make a pull request. If you're having trouble making a pull request (it's tricky!), check out [GitHub's guide](https://help.github.com/articles/using-pull-requests/) or add an issue. We'll make it work!
Please avoid using LLM/AI tools for work on Helmet.js. This is because (1) LLM-produced code may have copyright issues (2) LLM-based code is often lower quality, raising the bar for maintainers (3) LLMs have many ethical issues which this project wants to avoid.
================================================
FILE: LICENSE
================================================
The MIT License
Copyright (c) 2012-2026 Evan Hahn, Adam Baldwin
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================
# Helmet
Helmet helps secure Node/Express apps. It sets HTTP response headers such as `Content-Security-Policy` and `Strict-Transport-Security`. It aims to be quick to integrate and be low maintenance afterward.
## Quick start
```javascript
import helmet from "helmet";
const app = express();
app.use(helmet());
```
This will set 13 HTTP response headers in your app.
[Helmet can also be used in standalone Node.js, or with other frameworks.](https://helmetjs.github.io/faq/use-without-express/)
## Configuration
Each header can be disabled. To disable a header:
```js
// Disable the Content-Security-Policy and X-Download-Options headers
app.use(
helmet({
contentSecurityPolicy: false,
xDownloadOptions: false,
}),
);
```
To configure a header, pass header-specific options:
```js
// Configure the Content-Security-Policy header.
app.use(
helmet({
contentSecurityPolicy: {
directives: {
"script-src": ["'self'", "example.com"],
},
},
}),
);
```
## HTTP header reference
<details id="content-security-policy">
<summary><code>Content-Security-Policy</code></summary>
Default:
```http
Content-Security-Policy: default-src 'self';base-uri 'self';font-src 'self' https: data:;form-action 'self';frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests
```
The `Content-Security-Policy` header mitigates a large number of attacks, such as [cross-site scripting][XSS]. See [MDN's introductory article on Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP).
This header is powerful but likely requires some configuration for your specific app.
To configure this header, pass an object with a nested `directives` object. Each key is a directive name in camel case (such as `defaultSrc`) or kebab case (such as `default-src`). Each value is an array (or other iterable) of strings or functions for that directive. If a function appears in the array, it will be called with the request and response objects.
```javascript
// Sets all of the defaults, but overrides `script-src`
// and disables the default `style-src`.
app.use(
helmet({
contentSecurityPolicy: {
directives: {
"script-src": ["'self'", "example.com"],
"style-src": null,
},
},
}),
);
```
```js
// Sets the `script-src` directive to
// "'self' 'nonce-e33cc...'"
// (or similar)
app.use((req, res, next) => {
res.locals.cspNonce = crypto.randomBytes(32).toString("hex");
next();
});
app.use(
helmet({
contentSecurityPolicy: {
directives: {
scriptSrc: ["'self'", (req, res) => `'nonce-${res.locals.cspNonce}'`],
},
},
}),
);
```
These directives are merged into a default policy, which you can disable by setting `useDefaults` to `false`.
```javascript
// Sets "Content-Security-Policy: default-src 'self';
// script-src 'self' example.com;object-src 'none';
// upgrade-insecure-requests"
app.use(
helmet({
contentSecurityPolicy: {
useDefaults: false,
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "example.com"],
objectSrc: ["'none'"],
upgradeInsecureRequests: [],
},
},
}),
);
```
You can get the default directives object with `helmet.contentSecurityPolicy.getDefaultDirectives()`. Here is the default policy (formatted for readability):
```
default-src 'self';
base-uri 'self';
font-src 'self' https: data:;
form-action 'self';
frame-ancestors 'self';
img-src 'self' data:;
object-src 'none';
script-src 'self';
script-src-attr 'none';
style-src 'self' https: 'unsafe-inline';
upgrade-insecure-requests
```
The `default-src` directive can be explicitly disabled by setting its value to `helmet.contentSecurityPolicy.dangerouslyDisableDefaultSrc`, but this is not recommended.
You can set the [`Content-Security-Policy-Report-Only`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only) instead:
```javascript
// Sets the Content-Security-Policy-Report-Only header
app.use(
helmet({
contentSecurityPolicy: {
directives: {
/* ... */
},
reportOnly: true,
},
}),
);
```
`upgrade-insecure-requests`, a directive that causes browsers to upgrade HTTP to HTTPS, is set by default. You may wish to avoid this in development, as you may not be developing with HTTPS. Notably, Safari will upgrade `http://localhost` to `https://localhost`, which can cause problems. To work around this, you may wish to disable the `upgrade-insecure-requests` directive in development. For example:
```js
const isDevelopment = app.get("env") === "development";
app.use(
helmet({
contentSecurityPolicy: {
directives: {
// Disable upgrade-insecure-requests in development.
"upgrade-insecure-requests": isDevelopment ? null : [],
},
},
}),
);
```
Helmet performs very little validation on your CSP. You should rely on CSP checkers like [CSP Evaluator](https://csp-evaluator.withgoogle.com/) instead.
To disable the `Content-Security-Policy` header:
```js
app.use(
helmet({
contentSecurityPolicy: false,
}),
);
```
You can use this as standalone middleware with `app.use(helmet.contentSecurityPolicy())`.
</details>
<details id="cross-origin-embedder-policy">
<summary><code>Cross-Origin-Embedder-Policy</code></summary>
This header is not set by default.
The `Cross-Origin-Embedder-Policy` header helps control what resources can be loaded cross-origin. See [MDN's article on this header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy) for more.
```js
// Helmet does not set Cross-Origin-Embedder-Policy
// by default.
app.use(helmet());
// Sets "Cross-Origin-Embedder-Policy: require-corp"
app.use(helmet({ crossOriginEmbedderPolicy: true }));
// Sets "Cross-Origin-Embedder-Policy: credentialless"
app.use(helmet({ crossOriginEmbedderPolicy: { policy: "credentialless" } }));
```
You can use this as standalone middleware with `app.use(helmet.crossOriginEmbedderPolicy())`.
</details>
<details id="cross-origin-opener-policy">
<summary><code>Cross-Origin-Opener-Policy</code></summary>
Default:
```http
Cross-Origin-Opener-Policy: same-origin
```
The `Cross-Origin-Opener-Policy` header helps process-isolate your page. For more, see [MDN's article on this header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy).
```js
// Sets "Cross-Origin-Opener-Policy: same-origin"
app.use(helmet());
// Sets "Cross-Origin-Opener-Policy: same-origin-allow-popups"
app.use(
helmet({
crossOriginOpenerPolicy: { policy: "same-origin-allow-popups" },
}),
);
```
To disable the `Cross-Origin-Opener-Policy` header:
```js
app.use(
helmet({
crossOriginOpenerPolicy: false,
}),
);
```
You can use this as standalone middleware with `app.use(helmet.crossOriginOpenerPolicy())`.
</details>
<details id="cross-origin-resource-policy">
<summary><code>Cross-Origin-Resource-Policy</code></summary>
Default:
```http
Cross-Origin-Resource-Policy: same-origin
```
The `Cross-Origin-Resource-Policy` header blocks others from loading your resources cross-origin in some cases. For more, see ["Consider deploying Cross-Origin Resource Policy"](https://resourcepolicy.fyi/) and [MDN's article on this header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy).
```js
// Sets "Cross-Origin-Resource-Policy: same-origin"
app.use(helmet());
// Sets "Cross-Origin-Resource-Policy: same-site"
app.use(helmet({ crossOriginResourcePolicy: { policy: "same-site" } }));
```
To disable the `Cross-Origin-Resource-Policy` header:
```js
app.use(
helmet({
crossOriginResourcePolicy: false,
}),
);
```
You can use this as standalone middleware with `app.use(helmet.crossOriginResourcePolicy())`.
</details>
<details id="origin-agent-cluster">
<summary><code>Origin-Agent-Cluster</code></summary>
Default:
```http
Origin-Agent-Cluster: ?1
```
The `Origin-Agent-Cluster` header provides a mechanism to allow web applications to isolate their origins from other processes. Read more about it [in the spec](https://html.spec.whatwg.org/multipage/browsers.html#origin-keyed-agent-clusters).
This header takes no options and is set by default.
```js
// Sets "Origin-Agent-Cluster: ?1"
app.use(helmet());
```
To disable the `Origin-Agent-Cluster` header:
```js
app.use(
helmet({
originAgentCluster: false,
}),
);
```
You can use this as standalone middleware with `app.use(helmet.originAgentCluster())`.
</details>
<details id="referrer-policy">
<summary><code>Referrer-Policy</code></summary>
Default:
```http
Referrer-Policy: no-referrer
```
The `Referrer-Policy` header which controls what information is set in [the `Referer` request header][Referer]. See ["Referer header: privacy and security concerns"](https://developer.mozilla.org/en-US/docs/Web/Security/Referer_header:_privacy_and_security_concerns) and [the header's documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy) on MDN for more.
```js
// Sets "Referrer-Policy: no-referrer"
app.use(helmet());
```
`policy` is a string or array of strings representing the policy. If passed as an array, it will be joined with commas, which is useful when setting [a fallback policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy#Specifying_a_fallback_policy). It defaults to `no-referrer`.
```js
// Sets "Referrer-Policy: no-referrer"
app.use(
helmet({
referrerPolicy: {
policy: "no-referrer",
},
}),
);
// Sets "Referrer-Policy: origin,unsafe-url"
app.use(
helmet({
referrerPolicy: {
policy: ["origin", "unsafe-url"],
},
}),
);
```
To disable the `Referrer-Policy` header:
```js
app.use(
helmet({
referrerPolicy: false,
}),
);
```
You can use this as standalone middleware with `app.use(helmet.referrerPolicy())`.
</details>
<details id="strict-transport-security">
<summary><code>Strict-Transport-Security</code></summary>
Default:
```http
Strict-Transport-Security: max-age=31536000; includeSubDomains
```
The `Strict-Transport-Security` header tells browsers to prefer HTTPS instead of insecure HTTP. See [the documentation on MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security) for more.
```js
// Sets "Strict-Transport-Security: max-age=31536000; includeSubDomains"
app.use(helmet());
```
`maxAge` is the number of seconds browsers should remember to prefer HTTPS. If passed a non-integer, the value is rounded down. It defaults to 365 days.
`includeSubDomains` is a boolean which dictates whether to include the `includeSubDomains` directive, which makes this policy extend to subdomains. It defaults to `true`.
`preload` is a boolean. If true, it adds the `preload` directive, expressing intent to add your HSTS policy to browsers. See [the "Preloading Strict Transport Security" section on MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security#Preloading_Strict_Transport_Security) for more. It defaults to `false`.
```js
// Sets "Strict-Transport-Security: max-age=123456; includeSubDomains"
app.use(
helmet({
strictTransportSecurity: {
maxAge: 123456,
},
}),
);
// Sets "Strict-Transport-Security: max-age=123456"
app.use(
helmet({
strictTransportSecurity: {
maxAge: 123456,
includeSubDomains: false,
},
}),
);
// Sets "Strict-Transport-Security: max-age=123456; includeSubDomains; preload"
app.use(
helmet({
strictTransportSecurity: {
maxAge: 63072000,
preload: true,
},
}),
);
```
To disable the `Strict-Transport-Security` header:
```js
app.use(
helmet({
strictTransportSecurity: false,
}),
);
```
You may wish to disable this header for local development, as it can make your browser force redirects from `http://localhost` to `https://localhost`, which may not be desirable if you develop multiple apps using `localhost`. See [this issue](https://github.com/helmetjs/helmet/issues/451) for more discussion.
You can use this as standalone middleware with `app.use(helmet.strictTransportSecurity())`.
</details>
<details id="x-content-type-options">
<summary><code>X-Content-Type-Options</code></summary>
Default:
```http
X-Content-Type-Options: nosniff
```
The `X-Content-Type-Options` mitigates [MIME type sniffing](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#MIME_sniffing) which can cause security issues. See [documentation for this header on MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options) for more.
This header takes no options and is set by default.
```js
// Sets "X-Content-Type-Options: nosniff"
app.use(helmet());
```
To disable the `X-Content-Type-Options` header:
```js
app.use(
helmet({
xContentTypeOptions: false,
}),
);
```
You can use this as standalone middleware with `app.use(helmet.xContentTypeOptions())`.
</details>
<details id="x-dns-prefetch-control">
<summary><code>X-DNS-Prefetch-Control</code></summary>
Default:
```http
X-DNS-Prefetch-Control: off
```
The `X-DNS-Prefetch-Control` header helps control DNS prefetching, which can improve user privacy at the expense of performance. See [documentation on MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-DNS-Prefetch-Control) for more.
```js
// Sets "X-DNS-Prefetch-Control: off"
app.use(helmet());
```
`allow` is a boolean dictating whether to enable DNS prefetching. It defaults to `false`.
Examples:
```js
// Sets "X-DNS-Prefetch-Control: off"
app.use(
helmet({
xDnsPrefetchControl: { allow: false },
}),
);
// Sets "X-DNS-Prefetch-Control: on"
app.use(
helmet({
xDnsPrefetchControl: { allow: true },
}),
);
```
To disable the `X-DNS-Prefetch-Control` header and use the browser's default value:
```js
app.use(
helmet({
xDnsPrefetchControl: false,
}),
);
```
You can use this as standalone middleware with `app.use(helmet.xDnsPrefetchControl())`.
</details>
<details id="x-download-options">
<summary><code>X-Download-Options</code></summary>
Default:
```http
X-Download-Options: noopen
```
The `X-Download-Options` header is specific to Internet Explorer 8. It forces potentially-unsafe downloads to be saved, mitigating execution of HTML in your site's context. For more, see [this old post on MSDN](https://learn.microsoft.com/en-us/archive/blogs/ie/ie8-security-part-v-comprehensive-protection).
This header takes no options and is set by default.
```js
// Sets "X-Download-Options: noopen"
app.use(helmet());
```
To disable the `X-Download-Options` header:
```js
app.use(
helmet({
xDownloadOptions: false,
}),
);
```
You can use this as standalone middleware with `app.use(helmet.xDownloadOptions())`.
</details>
<details id="x-frame-options">
<summary><code>X-Frame-Options</code></summary>
Default:
```http
X-Frame-Options: SAMEORIGIN
```
The legacy `X-Frame-Options` header to help you mitigate [clickjacking attacks](https://en.wikipedia.org/wiki/Clickjacking). This header is superseded by [the `frame-ancestors` Content Security Policy directive](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors) but is still useful on old browsers or if no CSP is used. For more, see [the documentation on MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options).
```js
// Sets "X-Frame-Options: SAMEORIGIN"
app.use(helmet());
```
`action` is a string that specifies which directive to use—either `DENY` or `SAMEORIGIN`. (A legacy directive, `ALLOW-FROM`, is not supported by Helmet. [Read more here.](https://helmetjs.github.io/faq/x-frame-options-allow-from-directive/)) It defaults to `SAMEORIGIN`.
Examples:
```js
// Sets "X-Frame-Options: DENY"
app.use(
helmet({
xFrameOptions: { action: "deny" },
}),
);
// Sets "X-Frame-Options: SAMEORIGIN"
app.use(
helmet({
xFrameOptions: { action: "sameorigin" },
}),
);
```
To disable the `X-Frame-Options` header:
```js
app.use(
helmet({
xFrameOptions: false,
}),
);
```
You can use this as standalone middleware with `app.use(helmet.xFrameOptions())`.
</details>
<details id="x-permitted-cross-domain-policies">
<summary><code>X-Permitted-Cross-Domain-Policies</code></summary>
Default:
```http
X-Permitted-Cross-Domain-Policies: none
```
The `X-Permitted-Cross-Domain-Policies` header tells some clients (mostly Adobe products) your domain's policy for loading cross-domain content. See [the description on OWASP](https://owasp.org/www-project-secure-headers/) for more.
```js
// Sets "X-Permitted-Cross-Domain-Policies: none"
app.use(helmet());
```
`permittedPolicies` is a string that must be `"none"`, `"master-only"`, `"by-content-type"`, or `"all"`. It defaults to `"none"`.
Examples:
```js
// Sets "X-Permitted-Cross-Domain-Policies: none"
app.use(
helmet({
xPermittedCrossDomainPolicies: {
permittedPolicies: "none",
},
}),
);
// Sets "X-Permitted-Cross-Domain-Policies: by-content-type"
app.use(
helmet({
xPermittedCrossDomainPolicies: {
permittedPolicies: "by-content-type",
},
}),
);
```
To disable the `X-Permitted-Cross-Domain-Policies` header:
```js
app.use(
helmet({
xPermittedCrossDomainPolicies: false,
}),
);
```
You can use this as standalone middleware with `app.use(helmet.xPermittedCrossDomainPolicies())`.
</details>
<details id="x-powered-by">
<summary><code>X-Powered-By</code></summary>
Default: the `X-Powered-By` header, if present, is removed.
Helmet removes the `X-Powered-By` header, which is set by default in Express and some other frameworks. Removing the header offers very limited security benefits (see [this discussion](https://github.com/expressjs/express/pull/2813#issuecomment-159270428)) and is mostly removed to save bandwidth, but may thwart simplistic attackers.
Note: [Express has a built-in way to disable the `X-Powered-By` header](https://stackoverflow.com/a/12484642/804100), which you may wish to use instead.
The removal of this header takes no options. The header is removed by default.
To disable this behavior:
```js
// Not required, but recommended for Express users:
app.disable("x-powered-by");
// Ask Helmet to ignore the X-Powered-By header.
app.use(
helmet({
xPoweredBy: false,
}),
);
```
You can use this as standalone middleware with `app.use(helmet.xPoweredBy())`.
</details>
<details id="x-xss-protection">
<summary><code>X-XSS-Protection</code></summary>
Default:
```http
X-XSS-Protection: 0
```
Helmet disables browsers' buggy cross-site scripting filter by setting the legacy `X-XSS-Protection` header to `0`. See [discussion about disabling the header here](https://github.com/helmetjs/helmet/issues/230) and [documentation on MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection).
This header takes no options and is set by default.
To disable the `X-XSS-Protection` header:
```js
// This is not recommended.
app.use(
helmet({
xXssProtection: false,
}),
);
```
You can use this as standalone middleware with `app.use(helmet.xXssProtection())`.
</details>
[Referer]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referer
[MIME sniffing]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#mime_sniffing
[Clickjacking]: https://en.wikipedia.org/wiki/Clickjacking
[XSS]: https://developer.mozilla.org/en-US/docs/Glossary/Cross-site_scripting
================================================
FILE: SECURITY.md
================================================
# Security issue reporting & disclosure process
Please reach out if you think you've found a security issue.
Email Evan Hahn at <me@evanhahn.com>, on Signal at [EvanHahn.64](https://signal.me/#eu/vDide_HmUgHnNa0usMXq8oHAA0gnl5dzCqDeHyXhkeIbIiOcPVhCZKXIZteSqoc8), or [in other ways](https://evanhahn.com/contact).
My playbook for security issues:
- Acknowledge and address the concern as soon as possible
- Issue advisories (CVEs, for example) as needed. Public disclosure may be embargoed to give people time to update
- Consider patching non-current major versions depending on popularity and severity
================================================
FILE: build/build-package.ts
================================================
import rollupTypescript from "@rollup/plugin-typescript";
import zopfli from "node-zopfli";
import * as fsOriginal from "node:fs";
import * as os from "node:os";
import * as path from "node:path";
import { pipeline } from "node:stream";
import { fileURLToPath } from "node:url";
import { promisify } from "node:util";
import * as zlib from "node:zlib";
import prettier from "prettier";
import { type RollupBuild, rollup } from "rollup";
import rollupDts from "rollup-plugin-dts";
import { npm } from "./helpers.js";
const fs = fsOriginal.promises;
const pipe = promisify(pipeline);
// This shaves a few bytes off the built files while still keeping them readable.
// When testing on 4f550aab7ccf00a6dfe686d57195268b3ef06b1a, it reduces the tarball size by about 100 bytes.
// This should help installation performance slightly.
const PRETTIER_PREPACK_CRUSH_OPTIONS: prettier.Options = {
printWidth: 2000,
trailingComma: "none",
useTabs: true,
arrowParens: "avoid",
bracketSpacing: false,
semi: false,
};
const rootDir = path.join(path.dirname(fileURLToPath(import.meta.url)), "..");
const testFiles = path.join(rootDir, "test", "**");
/**
* Build a Helmet package into a tarball ready to be published with `npm publish`.
*/
export async function buildAndPack(
middlewareToBuild?: string,
): Promise<string> {
let entry: string;
let esm: boolean;
let packageOverrides: Record<string, unknown>;
let filesToCopy: readonly string[];
if (middlewareToBuild) {
const middlewareDir = path.join(rootDir, "middlewares", middlewareToBuild);
entry = path.join(middlewareDir, "index.ts");
esm = false;
packageOverrides = await readJsonObject(
path.join(middlewareDir, "package-overrides.json"),
);
filesToCopy = [
path.join(rootDir, "LICENSE"),
path.join(middlewareDir, "README.md"),
path.join(middlewareDir, "CHANGELOG.md"),
];
} else {
entry = path.join(rootDir, "index.ts");
esm = true;
packageOverrides = {};
filesToCopy = [
path.join(rootDir, "LICENSE"),
path.join(rootDir, "README.md"),
path.join(rootDir, "CHANGELOG.md"),
path.join(rootDir, "SECURITY.md"),
];
}
const distDir = await temporaryDirectory();
await Promise.all([
buildCjs({ entry, distDir }),
...(esm ? [buildMjs({ entry, distDir })] : []),
buildTypes({ esm, entry, distDir }),
buildPackageJson({ esm, packageOverrides, distDir }),
copyStaticFiles({ filesToCopy, distDir }),
]);
await prePackCrush(distDir);
const npmPackedTarball = await pack(distDir);
const crushedTarball = await postPackCrush(npmPackedTarball);
return crushedTarball;
}
function temporaryDirectory(): Promise<string> {
return fs.mkdtemp(path.join(os.tmpdir(), "helmet"));
}
async function buildCjs({
entry,
distDir,
}: Readonly<{ entry: string; distDir: string }>) {
const outputPath = path.join(distDir, "index.cjs");
console.log(`Building ${outputPath}...`);
const bundle = await rollupForJs({ entry, distDir });
await bundle.write({
file: outputPath,
exports: "named",
format: "cjs",
generatedCode: "es2015",
outro: [
"module.exports = exports.default;",
// Some bundlers import with CommonJS but then pull `default` off.
"module.exports.default = module.exports;",
].join("\n"),
});
await bundle.close();
console.log(`Built ${outputPath}.`);
}
async function buildMjs({
entry,
distDir,
}: Readonly<{ entry: string; distDir: string }>) {
const outputPath = path.join(distDir, "index.mjs");
console.log(`Building ${outputPath}...`);
const bundle = await rollupForJs({ entry, distDir });
await bundle.write({
file: outputPath,
format: "esm",
generatedCode: "es2015",
});
await bundle.close();
console.log(`Built ${outputPath}.`);
}
function rollupForJs({
entry,
distDir,
}: Readonly<{ entry: string; distDir: string }>): Promise<RollupBuild> {
return rollup({
input: entry,
plugins: [
rollupTypescript({
outDir: distDir,
exclude: [testFiles],
}),
],
});
}
async function buildTypes({
esm,
entry,
distDir,
}: Readonly<{ esm: boolean; entry: string; distDir: string }>) {
console.log("Building types...");
const bundle = await rollup({
input: entry,
external: ["node:http"],
plugins: [rollupDts()],
});
await Promise.all([
(async () => {
const cjsPath = path.join(distDir, "index.d.cts");
await bundle.write({
file: cjsPath,
format: "commonjs",
});
console.log(`Built ${cjsPath}.`);
})(),
(async () => {
if (!esm) {
return;
}
const esmPath = path.join(distDir, "index.d.mts");
await bundle.write({
file: esmPath,
format: "esm",
});
console.log(`Built ${esmPath}.`);
})(),
]);
await bundle.close();
}
async function buildPackageJson({
esm,
packageOverrides,
distDir,
}: Readonly<{
esm: boolean;
packageOverrides: Readonly<Record<string, unknown>>;
distDir: string;
}>) {
const outputPath = path.join(distDir, "package.json");
console.log(`Building ${outputPath}...`);
const devPackageJson = await readJsonObject(
path.join(rootDir, "package.json"),
);
const packageJson = {
name: "helmet",
description: "help secure Express/Connect apps with various HTTP headers",
version: devPackageJson.version,
author: "Adam Baldwin <adam@npmjs.com> (https://evilpacket.net)",
contributors: ["Evan Hahn <me@evanhahn.com> (https://evanhahn.com)"],
homepage: "https://helmetjs.github.io/",
bugs: {
url: "https://github.com/helmetjs/helmet/issues",
email: "me@evanhahn.com",
},
repository: {
type: "git",
url: "git://github.com/helmetjs/helmet.git",
},
funding: "https://github.com/sponsors/EvanHahn",
license: "MIT",
keywords: [
"express",
"security",
"headers",
"backend",
"content-security-policy",
"cross-origin-embedder-policy",
"cross-origin-opener-policy",
"cross-origin-resource-policy",
"origin-agent-cluster",
"referrer-policy",
"strict-transport-security",
"x-content-type-options",
"x-dns-prefetch-control",
"x-download-options",
"x-frame-options",
"x-permitted-cross-domain-policies",
"x-powered-by",
"x-xss-protection",
],
engines: devPackageJson.engines,
exports: {
...(esm ? { import: "./index.mjs" } : {}),
require: "./index.cjs",
},
// All supported versions of Node handle `exports`, but some build tools
// still use `main`, so we keep it around.
main: "./index.cjs",
// Support old TypeScript versions.
types: "./index.d.cts",
...packageOverrides,
};
await fs.writeFile(outputPath, JSON.stringify(packageJson));
console.log(`Built ${outputPath}.`);
}
async function readJsonObject(
path: fsOriginal.PathLike,
): Promise<Record<string, unknown>> {
const result: unknown = JSON.parse(await fs.readFile(path, "utf8"));
if (typeof result !== "object" || result === null) {
throw new Error("Got a non-object from JSON.parse()");
}
return result as Record<string, unknown>;
}
async function copyStaticFiles({
filesToCopy,
distDir,
}: Readonly<{ filesToCopy: readonly string[]; distDir: string }>) {
await Promise.all(
filesToCopy.map(async (source) => {
const basename = path.basename(source);
const dest = path.join(distDir, basename);
console.log(`Copying ${source} to ${dest}...`);
await fs.copyFile(source, dest);
console.log(`Copied ${source} to ${dest}.`);
}),
);
}
async function prePackCrush(distDir: string): Promise<void> {
const files = (await fs.readdir(distDir))
.map((file) => path.join(distDir, file))
.filter((file) => path.extname(file) !== ".md");
await Promise.all(
files.map(async (file) => {
const prettierInfo = await prettier.getFileInfo(file);
if (!prettierInfo.inferredParser) {
return;
}
console.log(`Crushing ${file}...`);
const oldContents = await fs.readFile(file, { encoding: "utf8" });
const newContents = await prettier.format(oldContents, {
filepath: file,
...PRETTIER_PREPACK_CRUSH_OPTIONS,
});
await fs.writeFile(file, newContents, { encoding: "utf8" });
console.log(`Crushed ${file}.`);
}),
);
}
async function pack(distDir: string): Promise<string> {
await npm(["pack"], { cwd: distDir });
const tempDirFiles = await fs.readdir(distDir);
const tarballName = tempDirFiles.find(
(file) => file.startsWith("helmet-") && file.endsWith(".tgz"),
);
if (!tarballName) {
throw new Error(
"Couldn't find helmet tarball in temp directory. Build is not set up correctly",
);
}
return path.join(distDir, tarballName);
}
async function postPackCrush(originalTarGz: string): Promise<string> {
const originalSize = (await fs.stat(originalTarGz)).size;
console.log(`Crushing ${originalTarGz} (size: ${originalSize})...`);
const crushedTarGz = originalTarGz.replace(".tgz", ".crushed.tgz");
const readOriginal = fsOriginal.createReadStream(originalTarGz);
const gunzip = zlib.createGunzip();
const gzip = zopfli.createGzip({ numiterations: 100 });
const writeCrushed = fsOriginal.createWriteStream(crushedTarGz);
await pipe(readOriginal, gunzip, gzip, writeCrushed);
const crushedSize = (await fs.stat(crushedTarGz)).size;
const savings = originalSize - crushedSize;
if (savings < 0) {
console.log("Original tarball was smaller");
return originalTarGz;
} else {
const ratio = crushedSize / originalSize;
console.log(
`Crushed into ${crushedTarGz}. Size: ${crushedSize}. Savings: ${savings} bytes (result is ${Math.round(
ratio * 100,
)}% the size)`,
);
return crushedTarGz;
}
}
const isMain =
import.meta.url.startsWith("file:") &&
process.argv[1] === fileURLToPath(import.meta.url);
if (isMain) {
if (process.argv.length > 3) {
throw new Error("Too many arguments");
}
const middlewareToBuild = process.argv[2];
buildAndPack(middlewareToBuild)
.then((finalTarballPath) => {
console.log(finalTarballPath);
})
.catch((err) => {
console.error(err);
process.exit(1);
});
}
================================================
FILE: build/helpers.ts
================================================
import * as childProcess from "node:child_process";
export const npm = (
args: readonly string[],
{ cwd }: Readonly<{ cwd: string }>,
): Promise<void> =>
new Promise((resolve, reject) => {
const proc = childProcess.spawn("npm", args, {
cwd,
stdio: ["inherit", "ignore", "inherit"],
});
proc.on("close", (code) => {
if (code === 0) {
resolve();
} else {
reject(new Error(`npm ${args.join(" ")} exited with code ${code}`));
}
});
});
================================================
FILE: eslint.config.js
================================================
import pluginJs from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";
export default [
{
files: ["**/*.{js,mjs,cjs,ts}"],
},
{ languageOptions: { globals: globals.node } },
pluginJs.configs.recommended,
...tseslint.configs.strict,
{
ignores: ["*.config.js", "coverage/**/**"],
},
{
languageOptions: {
parserOptions: {
projectService: {
allowDefaultProject: [
"test/project-setups/javascript-*/*.{js,mjs,cjs,ts}",
],
},
tsconfigRootDir: import.meta.dirname,
},
},
},
{
rules: {
"no-unused-vars": "off",
"@typescript-eslint/consistent-type-exports": "error",
"@typescript-eslint/consistent-type-imports": "error",
"@typescript-eslint/no-confusing-void-expression": "error",
"@typescript-eslint/no-duplicate-enum-values": "error",
"@typescript-eslint/no-duplicate-type-constituents": "error",
"@typescript-eslint/no-extraneous-class": "error",
"@typescript-eslint/no-import-type-side-effects": "error",
"@typescript-eslint/no-redundant-type-constituents": "error",
"@typescript-eslint/no-require-imports": "error",
"@typescript-eslint/no-unnecessary-condition": "error",
"@typescript-eslint/no-unnecessary-qualifier": "error",
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/no-useless-empty-export": "error",
"@typescript-eslint/prefer-readonly": "error",
"@typescript-eslint/prefer-regexp-exec": "error",
"@typescript-eslint/require-array-sort-compare": "error",
"@typescript-eslint/switch-exhaustiveness-check": "error",
},
},
{
files: ["test/**/*.{js,mjs,cjs,ts}"],
rules: {
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unsafe-argument": "off",
"@typescript-eslint/no-unsafe-assignment": "off",
},
},
{
files: ["test/project-setups/**/*.{js,mjs,cjs,ts}"],
rules: {
"@typescript-eslint/no-require-imports": "off",
"@typescript-eslint/no-unnecessary-condition": "off",
},
},
];
================================================
FILE: index.ts
================================================
import type { IncomingMessage, ServerResponse } from "node:http";
import contentSecurityPolicy, {
type ContentSecurityPolicyOptions,
} from "./middlewares/content-security-policy/index.js";
import crossOriginEmbedderPolicy, {
type CrossOriginEmbedderPolicyOptions,
} from "./middlewares/cross-origin-embedder-policy/index.js";
import crossOriginOpenerPolicy, {
type CrossOriginOpenerPolicyOptions,
} from "./middlewares/cross-origin-opener-policy/index.js";
import crossOriginResourcePolicy, {
type CrossOriginResourcePolicyOptions,
} from "./middlewares/cross-origin-resource-policy/index.js";
import originAgentCluster from "./middlewares/origin-agent-cluster/index.js";
import referrerPolicy, {
type ReferrerPolicyOptions,
} from "./middlewares/referrer-policy/index.js";
import strictTransportSecurity, {
type StrictTransportSecurityOptions,
} from "./middlewares/strict-transport-security/index.js";
import xContentTypeOptions from "./middlewares/x-content-type-options/index.js";
import xDnsPrefetchControl, {
type XDnsPrefetchControlOptions,
} from "./middlewares/x-dns-prefetch-control/index.js";
import xDownloadOptions from "./middlewares/x-download-options/index.js";
import xFrameOptions, {
type XFrameOptionsOptions,
} from "./middlewares/x-frame-options/index.js";
import xPermittedCrossDomainPolicies, {
type XPermittedCrossDomainPoliciesOptions,
} from "./middlewares/x-permitted-cross-domain-policies/index.js";
import xPoweredBy from "./middlewares/x-powered-by/index.js";
import xXssProtection from "./middlewares/x-xss-protection/index.js";
export type HelmetOptions = {
contentSecurityPolicy?: ContentSecurityPolicyOptions | boolean;
crossOriginEmbedderPolicy?: CrossOriginEmbedderPolicyOptions | boolean;
crossOriginOpenerPolicy?: CrossOriginOpenerPolicyOptions | boolean;
crossOriginResourcePolicy?: CrossOriginResourcePolicyOptions | boolean;
originAgentCluster?: boolean;
referrerPolicy?: ReferrerPolicyOptions | boolean;
} & (
| {
strictTransportSecurity?: StrictTransportSecurityOptions | boolean;
hsts?: never;
}
| {
hsts?: StrictTransportSecurityOptions | boolean;
strictTransportSecurity?: never;
}
) &
(
| { xContentTypeOptions?: boolean; noSniff?: never }
| { noSniff?: boolean; xContentTypeOptions?: never }
) &
(
| {
xDnsPrefetchControl?: XDnsPrefetchControlOptions | boolean;
dnsPrefetchControl?: never;
}
| {
dnsPrefetchControl?: XDnsPrefetchControlOptions | boolean;
xDnsPrefetchControl?: never;
}
) &
(
| { xDownloadOptions?: boolean; ieNoOpen?: never }
| { ieNoOpen?: boolean; xDownloadOptions?: never }
) &
(
| { xFrameOptions?: XFrameOptionsOptions | boolean; frameguard?: never }
| { frameguard?: XFrameOptionsOptions | boolean; xFrameOptions?: never }
) &
(
| {
xPermittedCrossDomainPolicies?:
| XPermittedCrossDomainPoliciesOptions
| boolean;
permittedCrossDomainPolicies?: never;
}
| {
permittedCrossDomainPolicies?:
| XPermittedCrossDomainPoliciesOptions
| boolean;
xPermittedCrossDomainPolicies?: never;
}
) &
(
| { xPoweredBy?: boolean; hidePoweredBy?: never }
| { hidePoweredBy?: boolean; xPoweredBy?: never }
) &
(
| { xXssProtection?: boolean; xssFilter?: never }
| { xssFilter?: boolean; xXssProtection?: never }
);
type MiddlewareFunction = (
req: IncomingMessage,
res: ServerResponse,
next: (error?: Error) => void,
) => void;
interface Helmet {
(
options?: Readonly<HelmetOptions>,
): (
req: IncomingMessage,
res: ServerResponse,
next: (err?: unknown) => void,
) => void;
contentSecurityPolicy: typeof contentSecurityPolicy;
crossOriginEmbedderPolicy: typeof crossOriginEmbedderPolicy;
crossOriginOpenerPolicy: typeof crossOriginOpenerPolicy;
crossOriginResourcePolicy: typeof crossOriginResourcePolicy;
originAgentCluster: typeof originAgentCluster;
referrerPolicy: typeof referrerPolicy;
strictTransportSecurity: typeof strictTransportSecurity;
xContentTypeOptions: typeof xContentTypeOptions;
xDnsPrefetchControl: typeof xDnsPrefetchControl;
xDownloadOptions: typeof xDownloadOptions;
xFrameOptions: typeof xFrameOptions;
xPermittedCrossDomainPolicies: typeof xPermittedCrossDomainPolicies;
xPoweredBy: typeof xPoweredBy;
xXssProtection: typeof xXssProtection;
// Legacy aliases
dnsPrefetchControl: typeof xDnsPrefetchControl;
frameguard: typeof xFrameOptions;
hidePoweredBy: typeof xPoweredBy;
hsts: typeof strictTransportSecurity;
ieNoOpen: typeof xDownloadOptions;
noSniff: typeof xContentTypeOptions;
permittedCrossDomainPolicies: typeof xPermittedCrossDomainPolicies;
xssFilter: typeof xXssProtection;
}
function getMiddlewareFunctionsFromOptions(
options: Readonly<HelmetOptions>,
): MiddlewareFunction[] {
const result: MiddlewareFunction[] = [];
switch (options.contentSecurityPolicy) {
case undefined:
case true:
result.push(contentSecurityPolicy());
break;
case false:
break;
default:
result.push(contentSecurityPolicy(options.contentSecurityPolicy));
break;
}
switch (options.crossOriginEmbedderPolicy) {
case undefined:
case false:
break;
case true:
result.push(crossOriginEmbedderPolicy());
break;
default:
result.push(crossOriginEmbedderPolicy(options.crossOriginEmbedderPolicy));
break;
}
switch (options.crossOriginOpenerPolicy) {
case undefined:
case true:
result.push(crossOriginOpenerPolicy());
break;
case false:
break;
default:
result.push(crossOriginOpenerPolicy(options.crossOriginOpenerPolicy));
break;
}
switch (options.crossOriginResourcePolicy) {
case undefined:
case true:
result.push(crossOriginResourcePolicy());
break;
case false:
break;
default:
result.push(crossOriginResourcePolicy(options.crossOriginResourcePolicy));
break;
}
switch (options.originAgentCluster) {
case undefined:
case true:
result.push(originAgentCluster());
break;
case false:
break;
default:
console.warn(
"Origin-Agent-Cluster does not take options. Remove the property to silence this warning.",
);
result.push(originAgentCluster());
break;
}
switch (options.referrerPolicy) {
case undefined:
case true:
result.push(referrerPolicy());
break;
case false:
break;
default:
result.push(referrerPolicy(options.referrerPolicy));
break;
}
if ("strictTransportSecurity" in options && "hsts" in options) {
throw new Error(
"Strict-Transport-Security option was specified twice. Remove the `hsts` option to fix this error.",
);
}
const strictTransportSecurityOption =
options.strictTransportSecurity ?? options.hsts;
switch (strictTransportSecurityOption) {
case undefined:
case true:
result.push(strictTransportSecurity());
break;
case false:
break;
default:
result.push(strictTransportSecurity(strictTransportSecurityOption));
break;
}
if ("xContentTypeOptions" in options && "noSniff" in options) {
throw new Error(
"X-Content-Type-Options option was specified twice. Remove the `noSniff` option to fix this error.",
);
}
const xContentTypeOptionsOption =
options.xContentTypeOptions ?? options.noSniff;
switch (xContentTypeOptionsOption) {
case undefined:
case true:
result.push(xContentTypeOptions());
break;
case false:
break;
default:
console.warn(
"X-Content-Type-Options does not take options. Remove the property to silence this warning.",
);
result.push(xContentTypeOptions());
break;
}
if ("xDnsPrefetchControl" in options && "dnsPrefetchControl" in options) {
throw new Error(
"X-DNS-Prefetch-Control option was specified twice. Remove the `dnsPrefetchControl` option to fix this error.",
);
}
const xDnsPrefetchControlOption =
options.xDnsPrefetchControl ?? options.dnsPrefetchControl;
switch (xDnsPrefetchControlOption) {
case undefined:
case true:
result.push(xDnsPrefetchControl());
break;
case false:
break;
default:
result.push(xDnsPrefetchControl(xDnsPrefetchControlOption));
break;
}
if ("xDownloadOptions" in options && "ieNoOpen" in options) {
throw new Error(
"X-Download-Options option was specified twice. Remove the `ieNoOpen` option to fix this error.",
);
}
const xDownloadOptionsOption = options.xDownloadOptions ?? options.ieNoOpen;
switch (xDownloadOptionsOption) {
case undefined:
case true:
result.push(xDownloadOptions());
break;
case false:
break;
default:
console.warn(
"X-Download-Options does not take options. Remove the property to silence this warning.",
);
result.push(xDownloadOptions());
break;
}
if ("xFrameOptions" in options && "frameguard" in options) {
throw new Error(
"X-Frame-Options option was specified twice. Remove the `frameguard` option to fix this error.",
);
}
const xFrameOptionsOption = options.xFrameOptions ?? options.frameguard;
switch (xFrameOptionsOption) {
case undefined:
case true:
result.push(xFrameOptions());
break;
case false:
break;
default:
result.push(xFrameOptions(xFrameOptionsOption));
break;
}
if (
"xPermittedCrossDomainPolicies" in options &&
"permittedCrossDomainPolicies" in options
) {
throw new Error(
"X-Permitted-Cross-Domain-Policies option was specified twice. Remove the `permittedCrossDomainPolicies` option to fix this error.",
);
}
const xPermittedCrossDomainPoliciesOption =
options.xPermittedCrossDomainPolicies ??
options.permittedCrossDomainPolicies;
switch (xPermittedCrossDomainPoliciesOption) {
case undefined:
case true:
result.push(xPermittedCrossDomainPolicies());
break;
case false:
break;
default:
result.push(
xPermittedCrossDomainPolicies(xPermittedCrossDomainPoliciesOption),
);
break;
}
if ("xPoweredBy" in options && "hidePoweredBy" in options) {
throw new Error(
"X-Powered-By option was specified twice. Remove the `hidePoweredBy` option to fix this error.",
);
}
const xPoweredByOption = options.xPoweredBy ?? options.hidePoweredBy;
switch (xPoweredByOption) {
case undefined:
case true:
result.push(xPoweredBy());
break;
case false:
break;
default:
console.warn(
"X-Powered-By does not take options. Remove the property to silence this warning.",
);
result.push(xPoweredBy());
break;
}
if ("xXssProtection" in options && "xssFilter" in options) {
throw new Error(
"X-XSS-Protection option was specified twice. Remove the `xssFilter` option to fix this error.",
);
}
const xXssProtectionOption = options.xXssProtection ?? options.xssFilter;
switch (xXssProtectionOption) {
case undefined:
case true:
result.push(xXssProtection());
break;
case false:
break;
default:
console.warn(
"X-XSS-Protection does not take options. Remove the property to silence this warning.",
);
result.push(xXssProtection());
break;
}
return result;
}
const helmet: Helmet = Object.assign(
function helmet(options: Readonly<HelmetOptions> = {}) {
// People should be able to pass an options object with no prototype,
// so we want this optional chaining.
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (options.constructor?.name === "IncomingMessage") {
throw new Error(
"It appears you have done something like `app.use(helmet)`, but it should be `app.use(helmet())`.",
);
}
const middlewareFunctions = getMiddlewareFunctionsFromOptions(options);
return function helmetMiddleware(
req: IncomingMessage,
res: ServerResponse,
next: (err?: unknown) => void,
): void {
let middlewareIndex = 0;
(function internalNext(err?: unknown) {
if (err) {
next(err);
return;
}
const middlewareFunction = middlewareFunctions[middlewareIndex];
if (middlewareFunction) {
middlewareIndex++;
middlewareFunction(req, res, internalNext);
} else {
next();
}
})();
};
},
{
contentSecurityPolicy,
crossOriginEmbedderPolicy,
crossOriginOpenerPolicy,
crossOriginResourcePolicy,
originAgentCluster,
referrerPolicy,
strictTransportSecurity,
xContentTypeOptions,
xDnsPrefetchControl,
xDownloadOptions,
xFrameOptions,
xPermittedCrossDomainPolicies,
xPoweredBy,
xXssProtection,
// Legacy aliases
dnsPrefetchControl: xDnsPrefetchControl,
xssFilter: xXssProtection,
permittedCrossDomainPolicies: xPermittedCrossDomainPolicies,
ieNoOpen: xDownloadOptions,
noSniff: xContentTypeOptions,
frameguard: xFrameOptions,
hidePoweredBy: xPoweredBy,
hsts: strictTransportSecurity,
},
);
export default helmet;
export {
contentSecurityPolicy,
crossOriginEmbedderPolicy,
crossOriginOpenerPolicy,
crossOriginResourcePolicy,
originAgentCluster,
referrerPolicy,
strictTransportSecurity,
xContentTypeOptions,
xDnsPrefetchControl,
xDownloadOptions,
xFrameOptions,
xPoweredBy,
xXssProtection,
// Legacy aliases
strictTransportSecurity as hsts,
xContentTypeOptions as noSniff,
xDnsPrefetchControl as dnsPrefetchControl,
xDownloadOptions as ieNoOpen,
xFrameOptions as frameguard,
xPermittedCrossDomainPolicies,
xPermittedCrossDomainPolicies as permittedCrossDomainPolicies,
xPoweredBy as hidePoweredBy,
xXssProtection as xssFilter,
};
================================================
FILE: middlewares/content-security-policy/CHANGELOG.md
================================================
# Changelog
## 4.0.0 - 2024-06-01
### Changed
- **Breaking:** `useDefaults` option now defaults to `true`
- **Breaking:** `form-action` directive is now set to `'self'` by default
- **Breaking:** `block-all-mixed-content` is no longer set by default
### Removed
- **Breaking:** Node 18+ is now required
## 3.4.0 - 2021-05-02
### Added
- New `useDefaults` option, defaulting to `false`, lets you selectively override defaults more easily
## 3.3.1 - 2020-12-27
### Fixed
- Broken TypeScript types. See [#283](https://github.com/helmetjs/helmet/issues/283)
## 3.3.0 - 2020-12-27
### Added
- Setting the `default-src` to `contentSecurityPolicy.dangerouslyDisableDefaultSrc` disables it
## 3.2.0 - 2020-11-01
### Added
- Get the default directives with `contentSecurityPolicy.getDefaultDirectives()`
## 3.1.0 - 2020-08-15
### Added
- Directive values can now include functions, as they could in Helmet 3. See [#243](https://github.com/helmetjs/helmet/issues/243)
## 3.0.0 - 2020-08-02
### Added
- If no `default-src` directive is supplied, an error is thrown
- Directive lists can be any iterable, not just arrays
### Changed
- There is now a default set of directives if none are supplied
- Duplicate keys now throw an error. See [helmetjs/csp#73](https://github.com/helmetjs/csp/issues/73)
- This middleware is more lenient, allowing more directive names or values
### Removed
- Removed browser sniffing (including the `browserSniff` parameter). See [#97](https://github.com/helmetjs/csp/issues/97)
- Removed conditional support. This includes directive functions and support for a function as the `reportOnly`. [Read this if you need help.](https://github.com/helmetjs/helmet/wiki/Conditionally-using-middleware)
- Removed a lot of checks—you should be checking your CSP with a different tool
- Removed support for legacy headers (and therefore the `setAllHeaders` parameter). [Read this if you need help.](https://github.com/helmetjs/helmet/wiki/Setting-legacy-Content-Security-Policy-headers-in-Helmet-4)
- Dropped support for old Node versions. Node 10+ is now required
- Removed the `loose` option
- Removed support for functions as directive values. You must supply an iterable of strings
- Removed the `disableAndroid` option
## 2.9.5 - 2020-02-22
### Changed
- Updated `bowser` subdependency from 2.7.0 to 2.9.0
### Fixed
- Fixed an issue some people were having when importing the `bowser` subdependency. See [#96](https://github.com/helmetjs/csp/issues/96) and [#101](https://github.com/helmetjs/csp/pull/101)
- Fixed a link in the readme. See [#100](https://github.com/helmetjs/csp/pull/100)
## 2.9.4 - 2019-10-21
### Changed
- Updated `bowser` subdependency from 2.6.1 to 2.7.0. See [#94](https://github.com/helmetjs/csp/pull/94)
## 2.9.3 - 2019-09-30
### Fixed
- Published a missing TypeScript type definition file. See [#90](https://github.com/helmetjs/csp/issues/90)
## 2.9.2 - 2019-09-20
### Fixed
- Fixed a bug where a request from Firefox 4 could delete `default-src` from future responses
- Fixed tablet PC detection by updating `bowser` subdependency to latest version
## 2.9.1 - 2019-09-04
### Changed
- Updated `bowser` subdependency from 2.5.3 to 2.5.4. See [#88](https://github.com/helmetjs/csp/pull/88)
### Fixed
- The "security" keyword was declared twice in package metadata. See [#87](https://github.com/helmetjs/csp/pull/87)
## 2.9.0 - 2019-08-28
### Added
- Added TypeScript type definitions. See [#86](https://github.com/helmetjs/csp/pull/86)
### Fixed
- Switched from `platform` to `bowser` to quiet a security vulnerability warning. See [#80](https://github.com/helmetjs/csp/issues/80)
## 2.8.0 - 2019-07-24
### Added
- Added a new `sandbox` directive, `allow-downloads-without-user-activation` (see [#85](https://github.com/helmetjs/csp/pull/85))
- Created a changelog
- Added some package metadata
### Changed
- Updated documentation to use ES2015
- Updated documentation to remove dependency on UUID package
- Updated `content-security-policy-builder` to 2.1.0
- Excluded some files from the npm package
Changes in versions 2.7.1 and below can be found in [Helmet's changelog](https://github.com/helmetjs/helmet/blob/master/CHANGELOG.md).
================================================
FILE: middlewares/content-security-policy/README.md
================================================
# Content Security Policy middleware
The `Content-Security-Policy` header mitigates a large number of attacks, such as [cross-site scripting][XSS]. See [MDN's introductory article on Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP).
This header is powerful but likely requires some configuration for your specific app.
To configure this header, pass an object with a nested `directives` object. Each key is a directive name in camel case (such as `defaultSrc`) or kebab case (such as `default-src`). Each value is an array (or other iterable) of strings or functions for that directive. If a function appears in the array, it will be called with the request and response objects.
```javascript
const contentSecurityPolicy = require("helmet-csp");
// Sets all of the defaults, but overrides `script-src`
// and disables the default `style-src`.
app.use(
contentSecurityPolicy({
directives: {
"script-src": ["'self'", "example.com"],
"style-src": null,
},
}),
);
```
```js
// Sets the `script-src` directive to
// "'self' 'nonce-e33cc...'"
// (or similar)
app.use((req, res, next) => {
res.locals.cspNonce = crypto.randomBytes(32).toString("hex");
next();
});
app.use(
contentSecurityPolicy({
directives: {
scriptSrc: ["'self'", (req, res) => `'nonce-${res.locals.cspNonce}'`],
},
}),
);
```
These directives are merged into a default policy, which you can disable by setting `useDefaults` to `false`.
```javascript
// Sets "Content-Security-Policy: default-src 'self';
// script-src 'self' example.com;object-src 'none';
// upgrade-insecure-requests"
app.use(
contentSecurityPolicy({
useDefaults: false,
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "example.com"],
objectSrc: ["'none'"],
upgradeInsecureRequests: [],
},
}),
);
```
You can get the default directives object with `contentSecurityPolicy.getDefaultDirectives()`. Here is the default policy (formatted for readability):
```
default-src 'self';
base-uri 'self';
font-src 'self' https: data:;
form-action 'self';
frame-ancestors 'self';
img-src 'self' data:;
object-src 'none';
script-src 'self';
script-src-attr 'none';
style-src 'self' https: 'unsafe-inline';
upgrade-insecure-requests
```
The `default-src` directive can be explicitly disabled by setting its value to `contentSecurityPolicy.dangerouslyDisableDefaultSrc`, but this is not recommended.
You can set the [`Content-Security-Policy-Report-Only`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only) instead:
```javascript
// Sets the Content-Security-Policy-Report-Only header
app.use(
contentSecurityPolicy({
directives: {
/* ... */
},
reportOnly: true,
}),
);
```
`upgrade-insecure-requests`, a directive that causes browsers to upgrade HTTP to HTTPS, is set by default. You may wish to avoid this in development, as you may not be developing with HTTPS. Notably, Safari will upgrade `http://localhost` to `https://localhost`, which can cause problems. To work around this, you may wish to disable the `upgrade-insecure-requests` directive in development. For example:
```js
const isDevelopment = app.get("env") === "development";
app.use(
contentSecurityPolicy({
directives: {
// Disable upgrade-insecure-requests in development.
"upgrade-insecure-requests": isDevelopment ? null : [],
},
}),
);
```
This module performs very little validation on your CSP. You should rely on CSP checkers like [CSP Evaluator](https://csp-evaluator.withgoogle.com/) instead.
================================================
FILE: middlewares/content-security-policy/index.ts
================================================
import type { IncomingMessage, ServerResponse } from "node:http";
type ContentSecurityPolicyDirectiveValueFunction = (
req: IncomingMessage,
res: ServerResponse,
) => string;
type ContentSecurityPolicyDirectiveValue =
| string
| ContentSecurityPolicyDirectiveValueFunction;
export interface ContentSecurityPolicyOptions {
useDefaults?: boolean;
directives?: Record<
string,
| null
| Iterable<ContentSecurityPolicyDirectiveValue>
| typeof dangerouslyDisableDefaultSrc
>;
reportOnly?: boolean;
}
type NormalizedDirectives = Map<
string,
Iterable<ContentSecurityPolicyDirectiveValue>
>;
interface ContentSecurityPolicy {
(
options?: Readonly<ContentSecurityPolicyOptions>,
): (
req: IncomingMessage,
res: ServerResponse,
next: (err?: Error) => void,
) => void;
getDefaultDirectives: typeof getDefaultDirectives;
dangerouslyDisableDefaultSrc: typeof dangerouslyDisableDefaultSrc;
}
const dangerouslyDisableDefaultSrc = Symbol("dangerouslyDisableDefaultSrc");
const SHOULD_BE_QUOTED: ReadonlySet<string> = new Set([
"none",
"self",
"strict-dynamic",
"report-sample",
"inline-speculation-rules",
"unsafe-inline",
"unsafe-eval",
"unsafe-hashes",
"wasm-unsafe-eval",
]);
const getDefaultDirectives = (): Record<
string,
Iterable<ContentSecurityPolicyDirectiveValue>
> => ({
"default-src": ["'self'"],
"base-uri": ["'self'"],
"font-src": ["'self'", "https:", "data:"],
"form-action": ["'self'"],
"frame-ancestors": ["'self'"],
"img-src": ["'self'", "data:"],
"object-src": ["'none'"],
"script-src": ["'self'"],
"script-src-attr": ["'none'"],
"style-src": ["'self'", "https:", "'unsafe-inline'"],
"upgrade-insecure-requests": [],
});
const dashify = (str: string): string =>
str.replace(/[A-Z]/g, (capitalLetter) => "-" + capitalLetter.toLowerCase());
const assertDirectiveValueIsValid = (
directiveName: string,
directiveValue: string,
): void => {
if (/;|,/.test(directiveValue)) {
throw new Error(
`Content-Security-Policy received an invalid directive value for ${JSON.stringify(
directiveName,
)}`,
);
}
};
const assertDirectiveValueEntryIsValid = (
directiveName: string,
directiveValueEntry: string,
): void => {
if (
SHOULD_BE_QUOTED.has(directiveValueEntry) ||
directiveValueEntry.startsWith("nonce-") ||
directiveValueEntry.startsWith("sha256-") ||
directiveValueEntry.startsWith("sha384-") ||
directiveValueEntry.startsWith("sha512-")
) {
throw new Error(
`Content-Security-Policy received an invalid directive value for ${JSON.stringify(
directiveName,
)}. ${JSON.stringify(directiveValueEntry)} should be quoted`,
);
}
};
function normalizeDirectives(
options: Readonly<ContentSecurityPolicyOptions>,
): NormalizedDirectives {
const defaultDirectives = getDefaultDirectives();
const { useDefaults = true, directives: rawDirectives = defaultDirectives } =
options;
const result: NormalizedDirectives = new Map();
const directiveNamesSeen = new Set<string>();
const directivesExplicitlyDisabled = new Set<string>();
for (const rawDirectiveName in rawDirectives) {
if (!Object.hasOwn(rawDirectives, rawDirectiveName)) {
continue;
}
if (
rawDirectiveName.length === 0 ||
/[^a-zA-Z0-9-]/.test(rawDirectiveName)
) {
throw new Error(
`Content-Security-Policy received an invalid directive name ${JSON.stringify(
rawDirectiveName,
)}`,
);
}
const directiveName = dashify(rawDirectiveName);
if (directiveNamesSeen.has(directiveName)) {
throw new Error(
`Content-Security-Policy received a duplicate directive ${JSON.stringify(
directiveName,
)}`,
);
}
directiveNamesSeen.add(directiveName);
const rawDirectiveValue = rawDirectives[rawDirectiveName];
let directiveValue: Iterable<ContentSecurityPolicyDirectiveValue>;
if (rawDirectiveValue === null) {
if (directiveName === "default-src") {
throw new Error(
"Content-Security-Policy needs a default-src but it was set to `null`. If you really want to disable it, set it to `contentSecurityPolicy.dangerouslyDisableDefaultSrc`.",
);
}
directivesExplicitlyDisabled.add(directiveName);
continue;
} else if (typeof rawDirectiveValue === "string") {
directiveValue = [rawDirectiveValue];
} else if (!rawDirectiveValue) {
throw new Error(
`Content-Security-Policy received an invalid directive value for ${JSON.stringify(
directiveName,
)}`,
);
} else if (rawDirectiveValue === dangerouslyDisableDefaultSrc) {
if (directiveName === "default-src") {
directivesExplicitlyDisabled.add("default-src");
continue;
} else {
throw new Error(
`Content-Security-Policy: tried to disable ${JSON.stringify(
directiveName,
)} as if it were default-src; simply omit the key`,
);
}
} else {
directiveValue = rawDirectiveValue;
}
for (const element of directiveValue) {
if (typeof element !== "string") continue;
assertDirectiveValueIsValid(directiveName, element);
assertDirectiveValueEntryIsValid(directiveName, element);
}
result.set(directiveName, directiveValue);
}
if (useDefaults) {
Object.entries(defaultDirectives).forEach(
([defaultDirectiveName, defaultDirectiveValue]) => {
if (
!result.has(defaultDirectiveName) &&
!directivesExplicitlyDisabled.has(defaultDirectiveName)
) {
result.set(defaultDirectiveName, defaultDirectiveValue);
}
},
);
}
if (!result.size) {
throw new Error(
"Content-Security-Policy has no directives. Either set some or disable the header",
);
}
if (
!result.has("default-src") &&
!directivesExplicitlyDisabled.has("default-src")
) {
throw new Error(
"Content-Security-Policy needs a default-src but none was provided. If you really want to disable it, set it to `contentSecurityPolicy.dangerouslyDisableDefaultSrc`.",
);
}
return result;
}
function getHeaderValue(
req: IncomingMessage,
res: ServerResponse,
normalizedDirectives: Readonly<NormalizedDirectives>,
): string | Error {
const result: string[] = [];
for (const [directiveName, rawDirectiveValue] of normalizedDirectives) {
let directiveValue = "";
for (const element of rawDirectiveValue) {
if (typeof element === "function") {
const newElement = element(req, res);
assertDirectiveValueEntryIsValid(directiveName, newElement);
directiveValue += " " + newElement;
} else {
directiveValue += " " + element;
}
}
if (directiveValue) {
assertDirectiveValueIsValid(directiveName, directiveValue);
result.push(`${directiveName}${directiveValue}`);
} else {
result.push(directiveName);
}
}
return result.join(";");
}
const contentSecurityPolicy: ContentSecurityPolicy =
function contentSecurityPolicy(
options: Readonly<ContentSecurityPolicyOptions> = {},
): (
req: IncomingMessage,
res: ServerResponse,
next: (err?: Error) => void,
) => void {
const headerName = options.reportOnly
? "Content-Security-Policy-Report-Only"
: "Content-Security-Policy";
const normalizedDirectives = normalizeDirectives(options);
return function contentSecurityPolicyMiddleware(
req: IncomingMessage,
res: ServerResponse,
next: (error?: Error) => void,
) {
const result = getHeaderValue(req, res, normalizedDirectives);
if (result instanceof Error) {
next(result);
} else {
res.setHeader(headerName, result);
next();
}
};
};
contentSecurityPolicy.getDefaultDirectives = getDefaultDirectives;
contentSecurityPolicy.dangerouslyDisableDefaultSrc =
dangerouslyDisableDefaultSrc;
export default contentSecurityPolicy;
export { dangerouslyDisableDefaultSrc, getDefaultDirectives };
================================================
FILE: middlewares/content-security-policy/package-overrides.json
================================================
{
"name": "helmet-csp",
"author": "Adam Baldwin <adam@npmjs.com> (https://evilpacket.net)",
"contributors": [
"Evan Hahn <me@evanhahn.com> (https://evanhahn.com)",
"Ryan Cannon <ryan@ryancannon.com> (https://ryancannon.com)"
],
"description": "Content Security Policy middleware",
"version": "4.0.0",
"keywords": ["express", "security", "content-security-policy", "csp", "xss"],
"engines": {
"node": ">=18.0.0"
}
}
================================================
FILE: middlewares/cross-origin-embedder-policy/index.ts
================================================
import type { IncomingMessage, ServerResponse } from "node:http";
export interface CrossOriginEmbedderPolicyOptions {
policy?: "require-corp" | "credentialless" | "unsafe-none";
}
const ALLOWED_POLICIES = new Set([
"require-corp",
"credentialless",
"unsafe-none",
]);
function getHeaderValueFromOptions({
policy = "require-corp",
}: Readonly<CrossOriginEmbedderPolicyOptions>): string {
if (ALLOWED_POLICIES.has(policy)) {
return policy;
} else {
throw new Error(
`Cross-Origin-Embedder-Policy does not support the ${JSON.stringify(
policy,
)} policy`,
);
}
}
function crossOriginEmbedderPolicy(
options: Readonly<CrossOriginEmbedderPolicyOptions> = {},
) {
const headerValue = getHeaderValueFromOptions(options);
return function crossOriginEmbedderPolicyMiddleware(
_req: IncomingMessage,
res: ServerResponse,
next: () => void,
) {
res.setHeader("Cross-Origin-Embedder-Policy", headerValue);
next();
};
}
export default crossOriginEmbedderPolicy;
================================================
FILE: middlewares/cross-origin-opener-policy/index.ts
================================================
import type { IncomingMessage, ServerResponse } from "node:http";
export interface CrossOriginOpenerPolicyOptions {
policy?:
| "same-origin"
| "same-origin-allow-popups"
| "noopener-allow-popups"
| "unsafe-none";
}
const ALLOWED_POLICIES = new Set([
"same-origin",
"same-origin-allow-popups",
"noopener-allow-popups",
"unsafe-none",
]);
function getHeaderValueFromOptions({
policy = "same-origin",
}: Readonly<CrossOriginOpenerPolicyOptions>): string {
if (ALLOWED_POLICIES.has(policy)) {
return policy;
} else {
throw new Error(
`Cross-Origin-Opener-Policy does not support the ${JSON.stringify(
policy,
)} policy`,
);
}
}
function crossOriginOpenerPolicy(
options: Readonly<CrossOriginOpenerPolicyOptions> = {},
) {
const headerValue = getHeaderValueFromOptions(options);
return function crossOriginOpenerPolicyMiddleware(
_req: IncomingMessage,
res: ServerResponse,
next: () => void,
) {
res.setHeader("Cross-Origin-Opener-Policy", headerValue);
next();
};
}
export default crossOriginOpenerPolicy;
================================================
FILE: middlewares/cross-origin-resource-policy/CHANGELOG.md
================================================
# Changelog
## Unreleased
### Changed
- **Breaking:** increase TypeScript strictness around arguments. Only affects TypeScript users. See [helmetjs/helmet#369](https://github.com/helmetjs/helmet/issues/369)
## 0.3.0 - 2021-04-17
### Added
- Added support for the `cross-origin` policy
## 0.2.1 - 2020-12-22
### Fixed
- Fixed incorrect example in README
## 0.2.0 - 2019-07-17
### Added
- Added TypeScript type definitions. See [#2](https://github.com/helmetjs/cross-origin-resource-policy/pull/2) and [helmetjs/helmet#188](https://github.com/helmetjs/helmet/issues/188)
- Created a changelog
- Added some additional package metadata: homepage, email for bug reports, and a list of supported Node versions
### Changed
- Excluded some files from npm package
This changelog was started in version 0.2.0.
================================================
FILE: middlewares/cross-origin-resource-policy/README.md
================================================
# Cross-Origin-Resource-Policy middleware
This middleware sets the `Cross-Origin-Resource-Policy` header. Read about it [in the spec](https://fetch.spec.whatwg.org/#cross-origin-resource-policy-header).
Usage:
```javascript
const crossOriginResourcePolicy = require("cross-origin-resource-policy");
// Sets "Cross-Origin-Resource-Policy: same-origin"
app.use(crossOriginResourcePolicy({ policy: "same-origin" }));
// Sets "Cross-Origin-Resource-Policy: same-site"
app.use(crossOriginResourcePolicy({ policy: "same-site" }));
```
================================================
FILE: middlewares/cross-origin-resource-policy/index.ts
================================================
import type { IncomingMessage, ServerResponse } from "node:http";
export interface CrossOriginResourcePolicyOptions {
policy?: "same-origin" | "same-site" | "cross-origin";
}
const ALLOWED_POLICIES = new Set(["same-origin", "same-site", "cross-origin"]);
function getHeaderValueFromOptions({
policy = "same-origin",
}: Readonly<CrossOriginResourcePolicyOptions>): string {
if (ALLOWED_POLICIES.has(policy)) {
return policy;
} else {
throw new Error(
`Cross-Origin-Resource-Policy does not support the ${JSON.stringify(
policy,
)} policy`,
);
}
}
function crossOriginResourcePolicy(
options: Readonly<CrossOriginResourcePolicyOptions> = {},
) {
const headerValue = getHeaderValueFromOptions(options);
return function crossOriginResourcePolicyMiddleware(
_req: IncomingMessage,
res: ServerResponse,
next: () => void,
) {
res.setHeader("Cross-Origin-Resource-Policy", headerValue);
next();
};
}
export default crossOriginResourcePolicy;
================================================
FILE: middlewares/cross-origin-resource-policy/package-overrides.json
================================================
{
"name": "cross-origin-resource-policy",
"author": "Evan Hahn <me@evanhahn.com> (https://evanhahn.com)",
"contributors": [],
"description": "Middleware to set the Cross-Origin-Resource-Policy header",
"version": "0.3.0",
"keywords": ["cross-origin-resource-policy"],
"engines": {
"node": ">=10.0.0"
}
}
================================================
FILE: middlewares/origin-agent-cluster/index.ts
================================================
import type { IncomingMessage, ServerResponse } from "node:http";
function originAgentCluster() {
return function originAgentClusterMiddleware(
_req: IncomingMessage,
res: ServerResponse,
next: () => void,
): void {
res.setHeader("Origin-Agent-Cluster", "?1");
next();
};
}
export default originAgentCluster;
================================================
FILE: middlewares/referrer-policy/CHANGELOG.md
================================================
# Changelog
## Unreleased
### Changed
- **Breaking:** increase TypeScript strictness around arguments. Only affects TypeScript users. See [helmetjs/helmet#369](https://github.com/helmetjs/helmet/issues/369)
## 2.0.0 - Unreleased
### Removed
- **Breaking:** Dropped support for old Node versions. Node 10+ is now required
## 1.2.0 - 2019-05-03
### Added
- Allow multiple values to be set. See [#7](https://github.com/helmetjs/referrer-policy/issues/7)
- Added TypeScript type definitions. See [helmetjs/helmet#188](https://github.com/helmetjs/helmet/issues/188)
- Created a changelog
### Changed
- Updated documentation
Changes in versions 1.1.0 and below can be found in [Helmet's changelog](https://github.com/helmetjs/helmet/blob/master/CHANGELOG.md).
================================================
FILE: middlewares/referrer-policy/README.md
================================================
# Referrer-Policy middleware
The [Referer HTTP header](https://en.wikipedia.org/wiki/HTTP_referer) is typically set by web browsers to tell the server where it's coming from. For example, if you click a link on _example.com/index.html_ that takes you to _wikipedia.org_, Wikipedia's servers will see `Referer: example.com`. This can have privacy implications—websites can see where you are coming from. The new [`Referrer-Policy` HTTP header](https://www.w3.org/TR/referrer-policy/#referrer-policy-header) lets authors control how browsers set the Referer header.
[Read the spec](https://www.w3.org/TR/referrer-policy/#referrer-policies) to see the options you can provide.
Usage:
```javascript
const referrerPolicy = require("referrer-policy");
app.use(referrerPolicy({ policy: "same-origin" }));
// Referrer-Policy: same-origin
app.use(referrerPolicy({ policy: "unsafe-url" }));
// Referrer-Policy: unsafe-url
app.use(
referrerPolicy({
policy: ["no-referrer", "unsafe-url"],
}),
);
// Referrer-Policy: no-referrer,unsafe-url
app.use(referrerPolicy());
// Referrer-Policy: no-referrer
```
================================================
FILE: middlewares/referrer-policy/index.ts
================================================
import type { IncomingMessage, ServerResponse } from "node:http";
type ReferrerPolicyToken =
| "no-referrer"
| "no-referrer-when-downgrade"
| "same-origin"
| "origin"
| "strict-origin"
| "origin-when-cross-origin"
| "strict-origin-when-cross-origin"
| "unsafe-url"
| "";
export interface ReferrerPolicyOptions {
policy?: ReferrerPolicyToken | ReferrerPolicyToken[];
}
const ALLOWED_TOKENS = new Set<ReferrerPolicyToken>([
"no-referrer",
"no-referrer-when-downgrade",
"same-origin",
"origin",
"strict-origin",
"origin-when-cross-origin",
"strict-origin-when-cross-origin",
"unsafe-url",
"",
]);
function getHeaderValueFromOptions({
policy = ["no-referrer"],
}: Readonly<ReferrerPolicyOptions>): string {
const tokens = typeof policy === "string" ? [policy] : policy;
if (tokens.length === 0) {
throw new Error("Referrer-Policy received no policy tokens");
}
const tokensSeen = new Set<ReferrerPolicyToken>();
tokens.forEach((token) => {
if (!ALLOWED_TOKENS.has(token)) {
throw new Error(
`Referrer-Policy received an unexpected policy token ${JSON.stringify(
token,
)}`,
);
} else if (tokensSeen.has(token)) {
throw new Error(
`Referrer-Policy received a duplicate policy token ${JSON.stringify(
token,
)}`,
);
}
tokensSeen.add(token);
});
return tokens.join(",");
}
function referrerPolicy(options: Readonly<ReferrerPolicyOptions> = {}) {
const headerValue = getHeaderValueFromOptions(options);
return function referrerPolicyMiddleware(
_req: IncomingMessage,
res: ServerResponse,
next: () => void,
) {
res.setHeader("Referrer-Policy", headerValue);
next();
};
}
export default referrerPolicy;
================================================
FILE: middlewares/referrer-policy/package-overrides.json
================================================
{
"name": "referrer-policy",
"author": "Evan Hahn <me@evanhahn.com> (https://evanhahn.com)",
"contributors": [],
"description": "Middleware to set the Referrer-Policy HTTP header",
"version": "1.2.0",
"keywords": [
"express",
"security",
"referer",
"referrer",
"referrer-policy",
"privacy"
],
"engines": {
"node": ">=10.0.0"
}
}
================================================
FILE: middlewares/strict-transport-security/CHANGELOG.md
================================================
# Changelog
## 3.0.0 - Unreleased
### Added
- TypeScript type definitions. See [#25](https://github.com/helmetjs/hsts/pull/25)
### Removed
- Dropped support for `includeSubdomains` with a lowercase D. See [#231](https://github.com/helmetjs/helmet/issues/231)
- Dropped support for `setIf`. [Read this if you need help.](https://github.com/helmetjs/helmet/wiki/Conditionally-using-middleware). See [#232](https://github.com/helmetjs/helmet/issues/232)
- Dropped support for old Node versions. Node 10+ is now required
## 2.2.0 - 2019-03-10
### Added
- Created a changelog
### Changed
- Mark the module as Node 4+ in the `engines` field of `package.json`
- Add a `homepage` in `package.json`
- Add an email to `package.json`'s `bugs` field
- Updated documentation
- Updated Adam Baldwin's contact info. See [helmetjs/helmet#189](https://github.com/helmetjs/helmet/issues/189)
### Deprecated
- The `setIf` option has been deprecated and will be removed in `hsts@3`. Refer to the documentation to see how to do without it. See [#22](https://github.com/helmetjs/hsts/issues/22) for more
- The `includeSubdomains` option (with a lowercase `d`) has been deprecated and will be removed in `hsts@3`. Use the uppercase-D `includeSubDomains` option instead. See [#21](https://github.com/helmetjs/hsts/issues/21) for more
Changes in versions 2.1.0 and below can be found in [Helmet's changelog](https://github.com/helmetjs/helmet/blob/master/CHANGELOG.md).
================================================
FILE: middlewares/strict-transport-security/README.md
================================================
# HTTP Strict Transport Security middleware
This middleware adds the `Strict-Transport-Security` header to the response. This tells browsers, "hey, only use HTTPS for the next period of time". ([See the spec](https://tools.ietf.org/html/rfc6797) for more.) Note that the header won't tell users on HTTP to _switch_ to HTTPS, it will just tell HTTPS users to stick around. You can enforce HTTPS with the [express-enforces-ssl](https://github.com/aredo/express-enforces-ssl) module.
This will set the Strict Transport Security header, telling browsers to visit by HTTPS for the next 365 days:
```javascript
const strictTransportSecurity = require("hsts");
// Sets "Strict-Transport-Security: max-age=31536000; includeSubDomains"
app.use(
strictTransportSecurity({
maxAge: 31536000, // 365 days in seconds
}),
);
```
Note that the max age must be in seconds.
The `includeSubDomains` directive is present by default. If this header is set on _example.com_, supported browsers will also use HTTPS on _my-subdomain.example.com_. You can disable this:
```javascript
app.use(
strictTransportSecurity({
maxAge: 31536000,
includeSubDomains: false,
}),
);
```
Some browsers let you submit your site's HSTS to be baked into the browser. You can add `preload` to the header with the following code. You can check your eligibility and submit your site at [hstspreload.org](https://hstspreload.org/).
```javascript
app.use(
strictTransportSecurity({
maxAge: 31536000, // Must be at least 1 year to be approved
includeSubDomains: true, // Must be enabled to be approved
preload: true,
}),
);
```
[The header is ignored in insecure HTTP](https://tools.ietf.org/html/rfc6797#section-8.1), so it's safe to set in development.
This header is [somewhat well-supported by browsers](https://caniuse.com/#feat=stricttransportsecurity).
================================================
FILE: middlewares/strict-transport-security/index.ts
================================================
import type { IncomingMessage, ServerResponse } from "node:http";
const DEFAULT_MAX_AGE = 365 * 24 * 60 * 60;
export interface StrictTransportSecurityOptions {
maxAge?: number;
includeSubDomains?: boolean;
preload?: boolean;
}
function parseMaxAge(value: number = DEFAULT_MAX_AGE): number {
if (value >= 0 && Number.isFinite(value)) {
return Math.floor(value);
} else {
throw new Error(
`Strict-Transport-Security: ${JSON.stringify(
value,
)} is not a valid value for maxAge. Please choose a positive integer.`,
);
}
}
function getHeaderValueFromOptions(
options: Readonly<StrictTransportSecurityOptions>,
): string {
if ("maxage" in options) {
throw new Error(
"Strict-Transport-Security received an unsupported property, `maxage`. Did you mean to pass `maxAge`?",
);
}
if ("includeSubdomains" in options) {
throw new Error(
'Strict-Transport-Security middleware should use `includeSubDomains` instead of `includeSubdomains`. (The correct one has an uppercase "D".)',
);
}
const directives: string[] = [`max-age=${parseMaxAge(options.maxAge)}`];
if (options.includeSubDomains === undefined || options.includeSubDomains) {
directives.push("includeSubDomains");
}
if (options.preload) {
directives.push("preload");
}
return directives.join("; ");
}
function strictTransportSecurity(
options: Readonly<StrictTransportSecurityOptions> = {},
) {
const headerValue = getHeaderValueFromOptions(options);
return function strictTransportSecurityMiddleware(
_req: IncomingMessage,
res: ServerResponse,
next: () => void,
) {
res.setHeader("Strict-Transport-Security", headerValue);
next();
};
}
export default strictTransportSecurity;
================================================
FILE: middlewares/strict-transport-security/package-overrides.json
================================================
{
"name": "hsts",
"description": "HTTP Strict Transport Security middleware",
"version": "2.2.0",
"keywords": [
"express",
"security",
"hsts",
"strict-transport-security",
"https"
],
"engines": {
"node": ">=10.0.0"
}
}
================================================
FILE: middlewares/x-content-type-options/CHANGELOG.md
================================================
# Changelog
## 2.0.0 - Unreleased
### Removed
- Dropped support for old Node versions. Node 10+ is now required
## 1.1.0 - 2019-05-11
### Added
- Added TypeScript type definitions. See [#4](https://github.com/helmetjs/dont-sniff-mimetype/issues/4) and [helmetjs/helmet#188](https://github.com/helmetjs/helmet/issues/188)
- Created a changelog
### Changed
- Updated some package metadata
- Excluded some files from npm package
Changes in versions 1.0.0 and below can be found in [Helmet's changelog](https://github.com/helmetjs/helmet/blob/master/CHANGELOG.md).
================================================
FILE: middlewares/x-content-type-options/README.md
================================================
# X-Content-Type-Options middleware
Some browsers will try to "sniff" mimetypes. For example, if my server serves _file.txt_ with a _text/plain_ content-type, some browsers can still run that file with `<script src="file.txt"></script>`. Many browsers will allow _file.js_ to be run even if the content-type isn't for JavaScript.
Browsers' same-origin policies generally prevent remote resources from being loaded dangerously, but vulnerabilities in web browsers can cause this to be abused. Some browsers, like [Chrome](https://developers.google.com/web/updates/2018/07/site-isolation), will further isolate memory if the `X-Content-Type-Options` header is seen.
There are [some other vulnerabilities](https://miki.it/blog/2014/7/8/abusing-jsonp-with-rosetta-flash/), too.
This middleware prevents Chrome, Opera 13+, IE 8+ and [Firefox 50+](https://bugzilla.mozilla.org/show_bug.cgi?id=471020) from doing this sniffing. The following example sets the `X-Content-Type-Options` header to its only option, `nosniff`:
```javascript
const dontSniffMimetype = require("dont-sniff-mimetype");
app.use(dontSniffMimetype());
```
[MSDN has a good description](https://msdn.microsoft.com/en-us/library/gg622941%28v=vs.85%29.aspx) of how browsers behave when this header is sent.
================================================
FILE: middlewares/x-content-type-options/index.ts
================================================
import type { IncomingMessage, ServerResponse } from "node:http";
function xContentTypeOptions() {
return function xContentTypeOptionsMiddleware(
_req: IncomingMessage,
res: ServerResponse,
next: () => void,
) {
res.setHeader("X-Content-Type-Options", "nosniff");
next();
};
}
export default xContentTypeOptions;
================================================
FILE: middlewares/x-content-type-options/package-overrides.json
================================================
{
"name": "dont-sniff-mimetype",
"description": "Middleware to prevent mimetype from being sniffed",
"version": "1.1.0",
"keywords": ["express", "security", "mimetype", "x-content-type-options"],
"engines": {
"node": ">=10.0.0"
}
}
================================================
FILE: middlewares/x-dns-prefetch-control/CHANGELOG.md
================================================
# Changelog
## Unreleased
### Removed
- Dropped support for old Node versions. Node 10+ is now required
## 0.3.0 - 2019-09-01
### Changed
- Dropped support for Node <8
## 0.2.0 - 2019-05-11
### Added
- Added TypeScript type definitions. See [#2](https://github.com/helmetjs/dns-prefetch-control/pull/2) and [helmetjs/helmet#188](https://github.com/helmetjs/helmet/issues/188)
- Created a changelog
### Changed
- Update some package metadata
- Excluded some files from npm package
Changes in versions 0.1.0 and below can be found in [Helmet's changelog](https://github.com/helmetjs/helmet/blob/master/CHANGELOG.md).
================================================
FILE: middlewares/x-dns-prefetch-control/README.md
================================================
# X-DNS-Prefetch-Control middleware
This middleware lets you set the `X-DNS-Prefetch-Control` to control browsers' DNS prefetching. Read more about it [on MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Controlling_DNS_prefetching) and [on Chromium's docs](https://dev.chromium.org/developers/design-documents/dns-prefetching).
Usage:
```js
const dnsPrefetchControl = require("dns-prefetch-control");
// Set X-DNS-Prefetch-Control: off
app.use(dnsPrefetchControl());
// Set X-DNS-Prefetch-Control: off
app.use(dnsPrefetchControl({ allow: false }));
// Set X-DNS-Prefetch-Control: on
app.use(dnsPrefetchControl({ allow: true }));
```
================================================
FILE: middlewares/x-dns-prefetch-control/index.ts
================================================
import type { IncomingMessage, ServerResponse } from "node:http";
export interface XDnsPrefetchControlOptions {
allow?: boolean;
}
function xDnsPrefetchControl(
options: Readonly<XDnsPrefetchControlOptions> = {},
) {
const headerValue = options.allow ? "on" : "off";
return function xDnsPrefetchControlMiddleware(
_req: IncomingMessage,
res: ServerResponse,
next: () => void,
): void {
res.setHeader("X-DNS-Prefetch-Control", headerValue);
next();
};
}
export default xDnsPrefetchControl;
================================================
FILE: middlewares/x-dns-prefetch-control/package-overrides.json
================================================
{
"name": "dns-prefetch-control",
"author": "Evan Hahn <me@evanhahn.com> (https://evanhahn.com)",
"contributors": [],
"description": "Middleware to set X-DNS-Prefetch-Control header.",
"version": "0.3.0",
"keywords": ["express", "security", "x-dns-prefetch-control", "prefetch"],
"engines": {
"node": ">=10.0.0"
}
}
================================================
FILE: middlewares/x-download-options/CHANGELOG.md
================================================
# Changelog
## 2.0.0 - Unreleased
- Dropped support for old Node versions. Node 10+ is now required
## 1.1.1 - 2020-06-16
### Changed
- Excluded more files from npm package
## 1.1.0 - 2019-03-10
### Added
- Added TypeScript type definitions. See [#1](https://github.com/helmetjs/ienoopen/pull/1) and [helmetjs/helmet#188](https://github.com/helmetjs/helmet/issues/188)
- Created a changelog
### Changed
- Updated documentation
- Excluded some files from npm package
Changes in versions 1.0.0 and below can be found in [Helmet's changelog](https://github.com/helmetjs/helmet/blob/master/CHANGELOG.md).
================================================
FILE: middlewares/x-download-options/README.md
================================================
# X-Download-Options middleware
This middleware sets the `X-Download-Options` header to `noopen` to prevent Internet Explorer users from executing downloads in your site's context.
```javascript
const ienoopen = require("ienoopen");
app.use(ienoopen());
```
Some web applications will serve untrusted HTML for download. By default, some versions of IE will allow you to open those HTML files _in the context of your site_, which means that an untrusted HTML page could start doing bad things in the context of your pages. For more, see [this MSDN blog post](https://docs.microsoft.com/en-us/archive/blogs/ie/ie8-security-part-v-comprehensive-protection).
This is pretty obscure, fixing a small bug on IE only. No real drawbacks other than performance/bandwidth of setting the headers, though.
================================================
FILE: middlewares/x-download-options/index.ts
================================================
import type { IncomingMessage, ServerResponse } from "node:http";
function xDownloadOptions() {
return function xDownloadOptionsMiddleware(
_req: IncomingMessage,
res: ServerResponse,
next: () => void,
): void {
res.setHeader("X-Download-Options", "noopen");
next();
};
}
export default xDownloadOptions;
================================================
FILE: middlewares/x-download-options/package-overrides.json
================================================
{
"name": "ienoopen",
"contributors": [
"Evan Hahn <me@evanhahn.com> (https://evanhahn.com)",
"Nathan Shively-Sanders <nathansa@microsoft.com> (https://github.com/sandersn)"
],
"description": "Middleware to set `X-Download-Options` header for IE8 security",
"version": "1.1.1",
"keywords": ["express", "security", "x-download-options"],
"engines": {
"node": ">=10.0.0"
}
}
================================================
FILE: middlewares/x-frame-options/CHANGELOG.md
================================================
# Changelog
## Unreleased
### Changed
- **Breaking:** increase TypeScript strictness around arguments. Only affects TypeScript users. See [helmetjs/helmet#369](https://github.com/helmetjs/helmet/issues/369)
- No longer offer a specific error when trying to use `ALLOW-FROM`; it just says that it is unsupported. Only the error message has changed
## 4.0.0 - 2020-12-21
### Removed
- Dropped support for the `ALLOW-FROM` action. [Read more here.](https://github.com/helmetjs/helmet/wiki/How-to-use-X%E2%80%93Frame%E2%80%93Options's-%60ALLOW%E2%80%93FROM%60-directive)
- Dropped support for old Node versions. Node 10+ is now required
## 3.1.0 - 2019-05-04
### Added
- Added TypeScript type definitions. See [#1](https://github.com/helmetjs/frameguard/pull/16) and [helmetjs/helmet#188](https://github.com/helmetjs/helmet/issues/188)
- Created a changelog
### Changed
- Updated some package metadata
- Update some documentation
- Excluded some files from npm package
Changes in versions 3.0.0 and below can be found in [Helmet's changelog](https://github.com/helmetjs/helmet/blob/master/CHANGELOG.md).
================================================
FILE: middlewares/x-frame-options/README.md
================================================
# X-Frame-Options middleware
The `X-Frame-Options` HTTP header restricts who can put your site in a frame which can help mitigate things like [clickjacking attacks](https://en.wikipedia.org/wiki/Clickjacking). The header has two modes: `DENY` and `SAMEORIGIN`.
This header is superseded by [the `frame-ancestors` Content Security Policy directive](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors) but is still useful on old browsers.
If your app does not need to be framed (and most don't) you can use `DENY`. If your site can be in frames from the same origin, you can set it to `SAMEORIGIN`.
Usage:
```javascript
const frameguard = require("frameguard");
// Don't allow me to be in ANY frames:
app.use(frameguard({ action: "deny" }));
// Only let me be framed by people of the same origin:
app.use(frameguard({ action: "sameorigin" }));
app.use(frameguard()); // defaults to sameorigin
```
A legacy action, `ALLOW-FROM`, is not supported by this middleware. [Read more here.](https://helmetjs.github.io/faq/x-frame-options-allow-from-directive/)
================================================
FILE: middlewares/x-frame-options/index.ts
================================================
import type { IncomingMessage, ServerResponse } from "node:http";
export interface XFrameOptionsOptions {
action?: "deny" | "sameorigin";
}
function getHeaderValueFromOptions({
action = "sameorigin",
}: Readonly<XFrameOptionsOptions>): string {
const normalizedAction =
typeof action === "string" ? action.toUpperCase() : action;
switch (normalizedAction) {
case "SAME-ORIGIN":
return "SAMEORIGIN";
case "DENY":
case "SAMEORIGIN":
return normalizedAction;
default:
throw new Error(
`X-Frame-Options received an invalid action ${JSON.stringify(action)}`,
);
}
}
function xFrameOptions(options: Readonly<XFrameOptionsOptions> = {}) {
const headerValue = getHeaderValueFromOptions(options);
return function xFrameOptionsMiddleware(
_req: IncomingMessage,
res: ServerResponse,
next: () => void,
) {
res.setHeader("X-Frame-Options", headerValue);
next();
};
}
export default xFrameOptions;
================================================
FILE: middlewares/x-frame-options/package-overrides.json
================================================
{
"name": "frameguard",
"description": "Middleware to set X-Frame-Options headers",
"version": "4.0.0",
"keywords": ["express", "security", "x-frame-options", "clickjack"],
"engines": {
"node": ">=10.0.0"
}
}
================================================
FILE: middlewares/x-permitted-cross-domain-policies/CHANGELOG.md
================================================
# Changelog
## Unreleased
### Changed
- **Breaking:** increase TypeScript strictness around arguments. Only affects TypeScript users. See [helmetjs/helmet#369](https://github.com/helmetjs/helmet/issues/369)
### Removed
- Dropped support for old Node versions. Node 14+ is now required
## 0.5.0 - 2019-09-01
## Changed
- Dropped support for Node <8
## 0.4.0 - 2019-06-15
### Added
- Added TypeScript type definitions. See [#7](https://github.com/helmetjs/crossdomain/issues/7)
- Created a changelog
- Added additional package metadata
### Changed
- Excluded some files from npm package
Changes in versions 0.3.0 and below can be found in [Helmet's changelog](https://github.com/helmetjs/helmet/blob/master/CHANGELOG.md).
================================================
FILE: middlewares/x-permitted-cross-domain-policies/README.md
================================================
# X-Permitted-Cross-Domain-Policies middleware
The `X-Permitted-Cross-Domain-Policies` header tells some web clients (like Adobe Flash or Adobe Acrobat) your domain's policy for loading cross-domain content. See the description on [OWASP](https://owasp.org/www-project-secure-headers/) for more.
Usage:
```javascript
const crossdomain = require("helmet-crossdomain");
// Sets X-Permitted-Cross-Domain-Policies: none
app.use(crossdomain());
// You can use any of the following values:
app.use(crossdomain({ permittedPolicies: "none" }));
app.use(crossdomain({ permittedPolicies: "master-only" }));
app.use(crossdomain({ permittedPolicies: "by-content-type" }));
app.use(crossdomain({ permittedPolicies: "all" }));
```
The `by-ftp-type` is not currently supported. Please open an issue or pull request if you desire this feature!
If you don't expect Adobe products to load data from your site, you get a minor security benefit by adding this header.
================================================
FILE: middlewares/x-permitted-cross-domain-policies/index.ts
================================================
import type { IncomingMessage, ServerResponse } from "node:http";
export interface XPermittedCrossDomainPoliciesOptions {
permittedPolicies?: "none" | "master-only" | "by-content-type" | "all";
}
const ALLOWED_PERMITTED_POLICIES = new Set([
"none",
"master-only",
"by-content-type",
"all",
]);
function getHeaderValueFromOptions({
permittedPolicies = "none",
}: Readonly<XPermittedCrossDomainPoliciesOptions>): string {
if (ALLOWED_PERMITTED_POLICIES.has(permittedPolicies)) {
return permittedPolicies;
} else {
throw new Error(
`X-Permitted-Cross-Domain-Policies does not support ${JSON.stringify(
permittedPolicies,
)}`,
);
}
}
function xPermittedCrossDomainPolicies(
options: Readonly<XPermittedCrossDomainPoliciesOptions> = {},
) {
const headerValue = getHeaderValueFromOptions(options);
return function xPermittedCrossDomainPoliciesMiddleware(
_req: IncomingMessage,
res: ServerResponse,
next: () => void,
) {
res.setHeader("X-Permitted-Cross-Domain-Policies", headerValue);
next();
};
}
export default xPermittedCrossDomainPolicies;
================================================
FILE: middlewares/x-permitted-cross-domain-policies/package-overrides.json
================================================
{
"name": "helmet-crossdomain",
"author": "Evan Hahn <me@evanhahn.com> (https://evanhahn.com)",
"contributors": [],
"description": "Set the X-Permitted-Cross-Domain-Policies header in Express apps",
"version": "0.5.0",
"keywords": [
"express",
"security",
"crossdomain.xml",
"x-permitted-cross-domain-policies"
],
"engines": {
"node": ">=10.0.0"
}
}
================================================
FILE: middlewares/x-powered-by/CHANGELOG.md
================================================
# Changelog
## 2.0.0 - Unreleased
### Removed
- Removed `setTo` option. See [this article](https://github.com/helmetjs/helmet/wiki/How-to-set-a-custom-X%E2%80%93Powered%E2%80%93By-header) to see how to replicate the removed behavior. See [#224](https://github.com/helmetjs/helmet/issues/224).
- Dropped support for old Node versions. Node 10+ is now required
## 1.1.0 - 2019-05-26
### Added
- Added TypeScript type definitions. See [#2](https://github.com/helmetjs/hide-powered-by/issues/2) and [helmetjs/helmet#188](https://github.com/helmetjs/helmet/issues/188)
- Created a changelog
### Changed
- Excluded some files from npm package
Changes in versions 1.0.0 and below can be found in [Helmet's changelog](https://github.com/helmetjs/helmet/blob/master/CHANGELOG.md).
================================================
FILE: middlewares/x-powered-by/README.md
================================================
# X-Powered-By middleware
Simple middleware to remove the `X-Powered-By` HTTP header if it's set.
Hackers can exploit known vulnerabilities in Express/Node if they see that your site is powered by Express (or whichever framework you use). For example, `X-Powered-By: Express` is sent in every HTTP request coming from Express, by default. This won't provide much security benefit ([as discussed here](https://github.com/expressjs/express/pull/2813#issuecomment-159270428)), but might help a tiny bit. It will also improve performance by reducing the number of bytes sent.
```javascript
const hidePoweredBy = require("hide-powered-by");
app.use(hidePoweredBy());
```
Note: if you're using Express, you don't need this middleware and can just do this:
```javascript
app.disable("x-powered-by");
```
================================================
FILE: middlewares/x-powered-by/index.ts
================================================
import type { IncomingMessage, ServerResponse } from "node:http";
function xPoweredBy() {
return function xPoweredByMiddleware(
_req: IncomingMessage,
res: ServerResponse,
next: () => void,
) {
res.removeHeader("X-Powered-By");
next();
};
}
export default xPoweredBy;
================================================
FILE: middlewares/x-powered-by/package-overrides.json
================================================
{
"name": "hide-powered-by",
"contributors": [
"Evan Hahn <me@evanhahn.com> (https://evanhahn.com)",
"Ameen Abdeen <ameen.abdeen.se@gmail.com>"
],
"description": "Middleware to remove the X-Powered-By header",
"version": "1.1.0",
"keywords": ["express", "security", "x-powered-by", "powered-by"],
"engines": {
"node": ">=10.0.0"
}
}
================================================
FILE: middlewares/x-xss-protection/CHANGELOG.md
================================================
# Changelog
## 2.0.0 - 2020-08-02
### Changed
- XSS filtering is now disabled by default. See [#230](https://github.com/helmetjs/helmet/issues/230)
### Removed
- No longer accepts options. Read ["How to disable blocking with X–XSS–Protection"](https://github.com/helmetjs/helmet/wiki/How-to-disable-blocking-with-X%E2%80%93XSS%E2%80%93Protection) and ["How to enable the `report` directive with X–XSS–Protection"](https://github.com/helmetjs/helmet/wiki/How-to-enable-the-%60report%60-directive-with-X%E2%80%93XSS%E2%80%93Protection) if you need the legacy behavior.
- Dropped support for old Node versions. Node 10+ is now required
## 1.3.0 - 2019-09-01
### Added
- Added `mode: null` to disable `mode=block`
### Changed
- Minor performance improvements with Internet Explorer <9 detection
## 1.2.0 - 2019-06-15
### Added
- Added TypeScript type definitions. See [#8](https://github.com/helmetjs/x-xss-protection/pull/8)
- Created a changelog
- Added some additional package metadata
### Changed
- Updated documentation
- Excluded some files from npm package
Changes in versions 1.1.0 and below can be found in [Helmet's changelog](https://github.com/helmetjs/helmet/blob/master/CHANGELOG.md).
================================================
FILE: middlewares/x-xss-protection/README.md
================================================
# X-XSS-Protection middleware
The `X-XSS-Protection` HTTP header aimed to offer a basic protection against cross-site scripting (XSS) attacks. _However, you probably should disable it_, which is what this middleware does.
Many browsers have chosen to remove it because of the unintended security issues it creates. Generally, you should protect against XSS with sanitization and a Content Security Policy. For more, read [this GitHub issue](https://github.com/helmetjs/helmet/issues/230).
This middleware sets the `X-XSS-Protection` header to `0`. For example:
```javascript
const xXssProtection = require("x-xss-protection");
// Set "X-XSS-Protection: 0"
app.use(xXssProtection());
```
If you truly need the legacy behavior, you can write your own simple middleware and avoid installing this module. For example:
```javascript
// NOTE: This is probably insecure!
app.use((req, res, next) => {
res.setHeader("X-XSS-Protection", "1; mode=block");
next();
});
```
================================================
FILE: middlewares/x-xss-protection/index.ts
================================================
import type { IncomingMessage, ServerResponse } from "node:http";
function xXssProtection() {
return function xXssProtectionMiddleware(
_req: IncomingMessage,
res: ServerResponse,
next: () => void,
) {
res.setHeader("X-XSS-Protection", "0");
next();
};
}
export default xXssProtection;
================================================
FILE: middlewares/x-xss-protection/package-overrides.json
================================================
{
"name": "x-xss-protection",
"description": "Middleware to disable the X-XSS-Protection header",
"version": "2.0.0",
"keywords": ["express", "security", "x-xss-protection"],
"engines": {
"node": ">=10.0.0"
}
}
================================================
FILE: package.json
================================================
{
"private": true,
"version": "8.1.0",
"devDependencies": {
"@eslint/js": "^10.0.1",
"@rollup/plugin-typescript": "^12.3.0",
"@types/connect": "^3.4.38",
"@types/node": "^25.5.0",
"@types/node-zopfli": "^2.0.5",
"@types/supertest": "^7.2.0",
"connect": "^3.7.0",
"eslint": "^10.0.3",
"globals": "^17.4.0",
"node-zopfli": "^2.1.4",
"npm-run-all2": "^8.0.4",
"prettier": "^3.8.1",
"rollup": "^4.59.0",
"rollup-plugin-dts": "^6.4.0",
"supertest": "^7.2.2",
"tslib": "^2.8.1",
"tsx": "^4.21.0",
"typescript": "^5.9.3",
"typescript-eslint": "^8.57.1"
},
"scripts": {
"test:eslint": "eslint --cache .",
"test:node": "tsx --test test/*.ts",
"test:prettier": "prettier --check .",
"test:typescript": "tsc --noEmit",
"format": "prettier --write .",
"clean": "node ./bin/clean.mjs",
"build": "tsx ./build/build-package.ts",
"test": "run-p --aggregate-output test:*"
},
"type": "module",
"engines": {
"node": ">=18.0.0"
}
}
================================================
FILE: test/content-security-policy.test.ts
================================================
import connect from "connect";
import assert from "node:assert/strict";
import { IncomingMessage, ServerResponse } from "node:http";
import { describe, it } from "node:test";
import supertest from "supertest";
import contentSecurityPolicy, {
dangerouslyDisableDefaultSrc,
getDefaultDirectives,
} from "../middlewares/content-security-policy";
import { check } from "./helpers";
const shouldBeQuoted = [
"none",
"self",
"strict-dynamic",
"report-sample",
"inline-speculation-rules",
"unsafe-inline",
"unsafe-eval",
"unsafe-hashes",
"wasm-unsafe-eval",
"nonce-abc123",
"sha256-ks9D5epDKP+c2x6DrkuHmhmfKkOM/HZ+pOlzdWbI91k=",
];
const getOwn = <T extends object, K extends keyof T>(
obj: T,
key: K,
): T[K] | undefined => (Object.hasOwn(obj, key) ? obj[key] : undefined);
async function checkCsp({
middlewareArgs,
expectedHeader = "content-security-policy",
expectedDirectives,
}: Readonly<{
middlewareArgs: Parameters<typeof contentSecurityPolicy>;
expectedHeader?: string;
expectedDirectives: Set<string>;
}>): Promise<void> {
const { header } = await check(contentSecurityPolicy(...middlewareArgs), {});
const headerValue = getOwn(header, expectedHeader);
assert(
typeof headerValue === "string",
`${expectedHeader} header should be set`,
);
const actualDirectives = new Set(headerValue.split(";"));
assert.deepEqual(actualDirectives, expectedDirectives);
}
describe("Content-Security-Policy middleware", () => {
it("sets a default policy when passed no directives", async () => {
const expectedDirectives = new Set([
"default-src 'self'",
"base-uri 'self'",
"font-src 'self' https: data:",
"form-action 'self'",
"frame-ancestors 'self'",
"img-src 'self' data:",
"object-src 'none'",
"script-src 'self'",
"script-src-attr 'none'",
"style-src 'self' https: 'unsafe-inline'",
"upgrade-insecure-requests",
]);
await checkCsp({
middlewareArgs: [],
expectedDirectives,
});
await checkCsp({
middlewareArgs: [{}],
expectedDirectives,
});
await checkCsp({
middlewareArgs: [Object.create(null)],
expectedDirectives,
});
await checkCsp({
middlewareArgs: [{ directives: undefined }],
expectedDirectives,
});
await checkCsp({
middlewareArgs: [{ useDefaults: true }],
expectedDirectives,
});
});
it("sets directives when named with snake-case", async () => {
await checkCsp({
middlewareArgs: [
{
useDefaults: false,
directives: {
"default-src": ["'self'"],
"script-src": ["example.com"],
"style-src": ["'none'"],
},
},
],
expectedDirectives: new Set([
"default-src 'self'",
"script-src example.com",
"style-src 'none'",
]),
});
});
it("sets directives when named with camelCase", async () => {
await checkCsp({
middlewareArgs: [
{
useDefaults: false,
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["example.com"],
styleSrc: ["'none'"],
},
},
],
expectedDirectives: new Set([
"default-src 'self'",
"script-src example.com",
"style-src 'none'",
]),
});
});
it("accepts a mix of snake-case and camelCase directive names", async () => {
await checkCsp({
middlewareArgs: [
{
useDefaults: false,
directives: {
"default-src": ["'self'"],
"script-src": ["example.com"],
styleSrc: ["'none'"],
objectSrc: ["'none'"],
},
},
],
expectedDirectives: new Set([
"default-src 'self'",
"script-src example.com",
"style-src 'none'",
"object-src 'none'",
]),
});
});
it("accepts an empty list of directive values", async () => {
await checkCsp({
middlewareArgs: [
{
useDefaults: false,
directives: {
"default-src": ["'self'"],
sandbox: [],
},
},
],
expectedDirectives: new Set(["default-src 'self'", "sandbox"]),
});
});
it("accepts non-array iterables for directive values", async () => {
await checkCsp({
middlewareArgs: [
{
useDefaults: false,
directives: {
"default-src": new Set(["'self'"]),
sandbox: {
[Symbol.iterator]: () => ({
next: () => ({
done: true,
value: undefined,
}),
}),
},
},
},
],
expectedDirectives: new Set(["default-src 'self'", "sandbox"]),
});
});
it("accepts strings as directive values", async () => {
await checkCsp({
middlewareArgs: [
{
useDefaults: false,
directives: {
"default-src": "'self' example.com",
scriptSrc: "'none'",
sandbox: "",
},
},
],
expectedDirectives: new Set([
"default-src 'self' example.com",
"script-src 'none'",
"sandbox",
]),
});
});
it("treats null directive values as nothing, as if they weren't set", async () => {
await checkCsp({
middlewareArgs: [
{
useDefaults: false,
directives: {
"default-src": "'self'",
scriptSrc: null,
},
},
],
expectedDirectives: new Set(["default-src 'self'"]),
});
});
it("allows functions in directive values to generate dynamic directives", async () => {
await checkCsp({
middlewareArgs: [
{
useDefaults: false,
directives: {
"default-src": [
"'self'",
(req: IncomingMessage, res: ServerResponse) => {
assert(
req instanceof IncomingMessage,
"req should be a request",
);
assert(
res instanceof ServerResponse,
"res should be a response",
);
return "foo.example.com";
},
"bar.example.com",
],
},
},
],
expectedDirectives: new Set([
"default-src 'self' foo.example.com bar.example.com",
]),
});
});
it("can override the default options", async () => {
const expectedDirectives = new Set([
"default-src 'self' example.com",
"font-src 'self' https: data:",
"form-action 'self'",
"frame-ancestors 'self'",
"img-src 'self' data:",
"object-src 'none'",
"script-src example.com",
"script-src-attr 'none'",
"style-src 'self' https: 'unsafe-inline'",
"upgrade-insecure-requests",
]);
await checkCsp({
middlewareArgs: [
{
useDefaults: true,
directives: {
"default-src": ["'self'", "example.com"],
"base-uri": null,
scriptSrc: ["example.com"],
},
},
],
expectedDirectives,
});
await checkCsp({
middlewareArgs: [
{
directives: {
"default-src": ["'self'", "example.com"],
"base-uri": null,
scriptSrc: ["example.com"],
},
},
],
expectedDirectives,
});
});
it('can set the "report only" version of the header instead', async () => {
await checkCsp({
middlewareArgs: [
{
useDefaults: false,
directives: {
"default-src": "'self'",
},
reportOnly: true,
},
],
expectedHeader: "content-security-policy-report-only",
expectedDirectives: new Set(["default-src 'self'"]),
});
});
it("throws if any directive names are invalid", () => {
const invalidNames = [
"",
";",
"\u00e1",
"default src",
"default;src",
"default,src",
"default!src",
"def\u00e1ult-src",
"default_src",
"__proto__",
];
for (const name of invalidNames) {
assert.throws(
() => {
contentSecurityPolicy({
useDefaults: true,
directives: {
[name]: ["value"],
},
});
},
{
message:
/^Content-Security-Policy received an invalid directive name "/,
},
);
}
});
it("throws if duplicate directive names are found", () => {
assert.throws(
() => {
contentSecurityPolicy({
useDefaults: false,
directives: {
defaultSrc: ["foo"],
"default-src": ["foo"],
},
});
},
{
message:
/^Content-Security-Policy received a duplicate directive "default-src"$/,
},
);
assert.throws(
() => {
contentSecurityPolicy({
useDefaults: false,
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["foo"],
"script-src": ["foo"],
},
});
},
{
message:
/^Content-Security-Policy received a duplicate directive "script-src"$/,
},
);
});
it("throws if any directive values are invalid", () => {
const invalidValues = [";", ",", "hello;world", "hello,world"];
for (const invalidValue of invalidValues) {
assert.throws(
() => {
contentSecurityPolicy({
useDefaults: false,
directives: {
"default-src": "'self'",
"something-else": [invalidValue],
},
});
},
{
message:
/^Content-Security-Policy received an invalid directive value for "something-else"$/,
},
);
}
for (const invalidDirectiveEntry of shouldBeQuoted) {
assert.throws(
() => {
contentSecurityPolicy({
useDefaults: false,
directives: {
"default-src": "'self'",
"something-else": [invalidDirectiveEntry],
},
});
},
{
message: `Content-Security-Policy received an invalid directive value for "something-else". "${invalidDirectiveEntry}" should be quoted`,
},
);
}
});
it("errors if any directive values are invalid when a function returns", async () => {
const badDirectiveValueEntries = ["bad;value", ...shouldBeQuoted];
await Promise.all(
badDirectiveValueEntries.map(async (directiveValueEntry) => {
const app = connect()
.use(
contentSecurityPolicy({
useDefaults: false,
directives: {
defaultSrc: ["'self'", () => directiveValueEntry],
},
}),
)
.use(
(
err: Error,
_req: IncomingMessage,
res: ServerResponse,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_next: () => void,
) => {
const isOk = err.message.startsWith(
'Content-Security-Policy received an invalid directive value for "default-src"',
);
res.end(JSON.stringify(isOk));
},
);
await supertest(app).get("/").expect(200, "true");
}),
);
});
it("throws if default-src is missing", () => {
assert.throws(
() => {
contentSecurityPolicy({
useDefaults: false,
directives: {},
});
},
{
message:
/^Content-Security-Policy has no directives. Either set some or disable the header$/,
},
);
assert.throws(
() => {
contentSecurityPolicy({
useDefaults: false,
directives: {
scriptSrc: ["example.com"],
},
});
},
{
message:
/^Content-Security-Policy needs a default-src but none was provided. If you really want to disable it, set it to `contentSecurityPolicy.dangerouslyDisableDefaultSrc`.$/,
},
);
assert.throws(
() => {
contentSecurityPolicy({
directives: { defaultSrc: null },
});
},
{
message:
/^Content-Security-Policy needs a default-src but it was set to `null`. If you really want to disable it, set it to `contentSecurityPolicy.dangerouslyDisableDefaultSrc`.$/,
},
);
// These should not throw.
contentSecurityPolicy({
useDefaults: false,
directives: {
defaultSrc: ["foo"],
},
});
contentSecurityPolicy({
useDefaults: false,
directives: {
"default-src": ["foo"],
},
});
contentSecurityPolicy({
useDefaults: false,
directives: {
defaultSrc: [],
},
});
contentSecurityPolicy({
useDefaults: false,
directives: {
defaultSrc: "",
},
});
});
it("allows default-src to be explicitly disabled", async () => {
await checkCsp({
middlewareArgs: [
{
useDefaults: false,
directives: {
defaultSrc: dangerouslyDisableDefaultSrc,
scriptSrc: ["example.com"],
},
},
],
expectedDirectives: new Set(["script-src example.com"]),
});
await checkCsp({
middlewareArgs: [
{
useDefaults: false,
directives: {
"default-src": dangerouslyDisableDefaultSrc,
"script-src": ["example.com"],
},
},
],
expectedDirectives: new Set(["script-src example.com"]),
});
await checkCsp({
middlewareArgs: [
{
useDefaults: true,
directives: {
"default-src": dangerouslyDisableDefaultSrc,
},
},
],
expectedDirectives: new Set([
"base-uri 'self'",
"font-src 'self' https: data:",
"form-action 'self'",
"frame-ancestors 'self'",
"img-src 'self' data:",
"object-src 'none'",
"script-src 'self'",
"script-src-attr 'none'",
"style-src 'self' https: 'unsafe-inline'",
"upgrade-insecure-requests",
]),
});
});
it("throws an error if default-src is disabled and there are no other directives", () => {
assert.throws(
() => {
contentSecurityPolicy({
useDefaults: false,
directives: {
defaultSrc: dangerouslyDisableDefaultSrc,
},
});
},
{
message:
/^Content-Security-Policy has no directives. Either set some or disable the header$/,
},
);
assert.throws(
() => {
contentSecurityPolicy({
useDefaults: false,
directives: {
"default-src": dangerouslyDisableDefaultSrc,
},
});
},
{
message:
/^Content-Security-Policy has no directives. Either set some or disable the header$/,
},
);
});
it("throws an error if directives other than default-src are `dangerouslyDisableDefaultSrc`", () => {
assert.throws(
() => {
contentSecurityPolicy({
directives: {
"default-src": "'self'",
"script-src": dangerouslyDisableDefaultSrc,
},
});
},
{
message:
/^Content-Security-Policy: tried to disable "script-src" as if it were default-src; simply omit the key$/,
},
);
});
});
describe("getDefaultDirectives", () => {
it("returns the middleware's default directives", () => {
assert.deepEqual(getDefaultDirectives(), {
"base-uri": ["'self'"],
"default-src": ["'self'"],
"font-src": ["'self'", "https:", "data:"],
"form-action": ["'self'"],
"frame-ancestors": ["'self'"],
"img-src": ["'self'", "data:"],
"object-src": ["'none'"],
"script-src": ["'self'"],
"script-src-attr": ["'none'"],
"style-src": ["'self'", "https:", "'unsafe-inline'"],
"upgrade-insecure-requests": [],
});
});
it("attaches itself to the top-level function", () => {
assert.equal(
getDefaultDirectives,
contentSecurityPolicy.getDefaultDirectives,
);
});
it("returns a new copy each time", () => {
const one = getDefaultDirectives();
one["worker-src"] = ["ignored.example"];
(one["img-src"] as Array<string>).push("ignored.example");
const two = getDefaultDirectives();
assert(!("worker-src" in two));
assert(
two["img-src"] && !Array.from(two["img-src"]).includes("ignored.example"),
);
});
});
================================================
FILE: test/cross-origin-embedder-policy.test.ts
================================================
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import crossOriginEmbedderPolicy from "../middlewares/cross-origin-embedder-policy";
import { check } from "./helpers";
describe("Cross-Origin-Embedder-Policy middleware", () => {
it('sets "Cross-Origin-Embedder-Policy: same-origin" when called with no policy', async () => {
const expectedHeaders = {
"cross-origin-embedder-policy": "require-corp",
};
await check(crossOriginEmbedderPolicy(), expectedHeaders);
await check(crossOriginEmbedderPolicy({}), expectedHeaders);
await check(
crossOriginEmbedderPolicy(Object.create(null)),
expectedHeaders,
);
await check(
crossOriginEmbedderPolicy({ policy: undefined }),
expectedHeaders,
);
});
(["require-corp", "credentialless", "unsafe-none"] as const).forEach(
(policy) => {
it(`sets "Cross-Origin-Embedder-Policy: ${policy}" when told to`, async () => {
await check(crossOriginEmbedderPolicy({ policy }), {
"cross-origin-embedder-policy": policy,
});
});
},
);
it("throws when setting the policy to an invalid value", () => {
const invalidValues = [
"",
"foo",
"CREDENTIALLESS",
123,
null,
new String("credentialless"),
];
for (const policy of invalidValues) {
assert.throws(
() => crossOriginEmbedderPolicy({ policy: policy as any }),
{
message: /^Cross-Origin-Embedder-Policy does not support /,
},
);
}
});
});
================================================
FILE: test/cross-origin-opener-policy.test.ts
================================================
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import crossOriginOpenerPolicy from "../middlewares/cross-origin-opener-policy";
import { check } from "./helpers";
describe("Cross-Origin-Opener-Policy middleware", () => {
it('sets "Cross-Origin-Opener-Policy: same-origin" when called with no policy', async () => {
const expectedHeaders = {
"cross-origin-opener-policy": "same-origin",
};
await check(crossOriginOpenerPolicy(), expectedHeaders);
await check(crossOriginOpenerPolicy({}), expectedHeaders);
await check(crossOriginOpenerPolicy(Object.create(null)), expectedHeaders);
await check(
crossOriginOpenerPolicy({ policy: undefined }),
expectedHeaders,
);
});
(
[
"same-origin",
"same-origin-allow-popups",
"noopener-allow-popups",
"unsafe-none",
] as const
).forEach((policy) => {
it(`sets "Cross-Origin-Opener-Policy: ${policy}" when told to`, async () => {
await check(crossOriginOpenerPolicy({ policy }), {
"cross-origin-opener-policy": policy,
});
});
});
it("throws when setting the policy to an invalid value", () => {
const invalidValues = [
"",
"foo",
"SAME-ORIGIN",
123,
null,
new String("same-origin"),
];
for (const policy of invalidValues) {
assert.throws(() => crossOriginOpenerPolicy({ policy: policy as any }), {
message: /^Cross-Origin-Opener-Policy does not support /,
});
}
});
});
================================================
FILE: test/cross-origin-resource-policy.test.ts
================================================
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import crossOriginResourcePolicy from "../middlewares/cross-origin-resource-policy";
import { check } from "./helpers";
describe("Cross-Origin-Resource-Policy middleware", () => {
it('sets "Cross-Origin-Resource-Policy: same-origin" when called with no policy', async () => {
const expectedHeaders = {
"cross-origin-resource-policy": "same-origin",
};
await check(crossOriginResourcePolicy(), expectedHeaders);
await check(crossOriginResourcePolicy({}), expectedHeaders);
await check(
crossOriginResourcePolicy(Object.create(null)),
expectedHeaders,
);
await check(
crossOriginResourcePolicy({ policy: undefined }),
expectedHeaders,
);
});
(["same-origin", "same-site", "cross-origin"] as const).forEach((policy) => {
it(`sets "Cross-Origin-Resource-Policy: ${policy}" when told to`, async () => {
await check(crossOriginResourcePolicy({ policy }), {
"cross-origin-resource-policy": policy,
});
});
});
it("throws when setting the policy to an invalid value", () => {
const invalidValues = [
"",
"foo",
"CROSS-ORIGIN",
123,
null,
new String("none"),
];
for (const policy of invalidValues) {
assert.throws(
() => crossOriginResourcePolicy({ policy: policy as any }),
{ message: /^Cross-Origin-Resource-Policy does not support / },
);
}
});
});
================================================
FILE: test/helpers.ts
================================================
import connect from "connect";
import assert from "node:assert/strict";
import type { IncomingMessage, ServerResponse } from "node:http";
import supertest from "supertest";
type MiddlewareFunction = (
req: IncomingMessage,
res: ServerResponse,
next: () => void,
) => void;
export async function check(
middleware: MiddlewareFunction,
expectedHeaders: Readonly<Record<string, string | null>>,
) {
const app = connect()
.use((_req, res, next) => {
res.setHeader("X-Powered-By", "Helmet test");
next();
})
.use(middleware)
.use((_req: IncomingMessage, res: ServerResponse) => {
res.end("Hello world!");
});
const response = await supertest(app).get("/").expect(200, "Hello world!");
for (const [headerName, headerValue] of Object.entries(expectedHeaders)) {
if (headerValue === null) {
assert(
!(headerName in response.header),
`${headerName} should not be set`,
);
} else {
assert.equal(
response.header[headerName],
headerValue,
`${headerName} should have value ${headerValue}`,
);
}
}
return response;
}
================================================
FILE: test/index.test.ts
================================================
import connect from "connect";
import assert from "node:assert/strict";
import type { IncomingMessage, ServerResponse } from "node:http";
import { describe, it, type TestContext, type Mock } from "node:test";
import supertest from "supertest";
import { check } from "./helpers";
import * as helmet from "..";
import contentSecurityPolicy from "../middlewares/content-security-policy";
import crossOriginEmbedderPolicy from "../middlewares/cross-origin-embedder-policy";
import crossOriginOpenerPolicy from "../middlewares/cross-origin-opener-policy";
import crossOriginResourcePolicy from "../middlewares/cross-origin-resource-policy";
import originAgentCluster from "../middlewares/origin-agent-cluster";
import referrerPolicy from "../middlewares/referrer-policy";
import strictTransportSecurity from "../middlewares/strict-transport-security";
import xContentTypeOptions from "../middlewares/x-content-type-options";
import xDnsPrefetchControl from "../middlewares/x-dns-prefetch-control";
import xDownloadOptions from "../middlewares/x-download-options";
import xFrameOptions from "../middlewares/x-frame-options";
import xPermittedCrossDomainPolicies from "../middlewares/x-permitted-cross-domain-policies";
import xPoweredBy from "../middlewares/x-powered-by";
import xXssProtection from "../middlewares/x-xss-protection";
describe("helmet", () => {
const topLevel = helmet.default;
it("includes all middleware, except COEP, with their default options", async () => {
// NOTE: This test relies on the CSP object being ordered a certain way,
// which could change (and be non-breaking). If that becomes a problem,
// we should update this test to be more robust.
const expectedHeaders = {
"content-security-policy":
"default-src 'self';base-uri 'self';font-src 'self' https: data:;form-action 'self';frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests",
"cross-origin-embedder-policy": null,
"cross-origin-opener-policy": "same-origin",
"cross-origin-resource-policy": "same-origin",
"origin-agent-cluster": "?1",
"referrer-policy": "no-referrer",
"strict-transport-security": "max-age=31536000; includeSubDomains",
"x-content-type-options": "nosniff",
"x-dns-prefetch-control": "off",
"x-download-options": "noopen",
"x-frame-options": "SAMEORIGIN",
"x-permitted-cross-domain-policies": "none",
"x-powered-by": null,
"x-xss-protection": "0",
};
await check(topLevel(), expectedHeaders);
await check(topLevel({}), expectedHeaders);
await check(topLevel(Object.create(null)), expectedHeaders);
});
it("allows individual middlewares to be disabled", async () => {
await check(topLevel({ contentSecurityPolicy: false }), {
"content-security-policy": null,
});
await check(topLevel({ xDnsPrefetchControl: false }), {
"x-dns-prefetch-control": null,
});
});
it("works with all default middlewares disabled", async () => {
await check(
topLevel({
contentSecurityPolicy: false,
crossOriginEmbedderPolicy: false,
crossOriginOpenerPolicy: false,
crossOriginResourcePolicy: false,
originAgentCluster: false,
referrerPolicy: false,
strictTransportSecurity: false,
xContentTypeOptions: false,
xDnsPrefetchControl: false,
xDownloadOptions: false,
xFrameOptions: false,
xPermittedCrossDomainPolicies: false,
xPoweredBy: false,
xXssProtection: false,
}),
{
"content-security-policy": null,
"x-frame-options": null,
},
);
});
it("errors when `use`d directly", () => {
const fakeRequest = {
constructor: {
name: "IncomingMessage",
},
};
assert.throws(() => topLevel(fakeRequest as any));
});
it("allows default middleware to be explicitly enabled (a no-op)", async () => {
await check(topLevel({ xFrameOptions: true }), {
"x-frame-options": "SAMEORIGIN",
});
});
it("allows Cross-Origin-Embedder-Policy middleware to be explicitly enabled", async () => {
await check(topLevel({ crossOriginEmbedderPolicy: true }), {
"cross-origin-embedder-policy": "require-corp",
});
});
it("allows Cross-Origin-Embedder-Policy middleware to be explicitly disabled", async () => {
await check(topLevel({ crossOriginEmbedderPolicy: false }), {
"cross-origin-embedder-policy": null,
});
});
it("allows Cross-Origin-Embedder-Policy middleware to be enabled with custom arguments", async () => {
await check(
topLevel({ crossOriginEmbedderPolicy: { policy: "credentialless" } }),
{
"cross-origin-embedder-policy": "credentialless",
},
);
});
it("allows Cross-Origin-Opener-Policy middleware to be enabled with its default", async () => {
await check(topLevel({ crossOriginOpenerPolicy: true }), {
"cross-origin-opener-policy": "same-origin",
});
});
it("allows Cross-Origin-Opener-Policy middleware to be enabled with custom arguments", async () => {
await check(
topLevel({
crossOriginOpenerPolicy: { policy: "same-origin-allow-popups" },
}),
{
"cross-origin-opener-policy": "same-origin-allow-popups",
},
);
});
it("allows Cross-Origin-Opener-Policy middleware to be explicitly disabled", async () => {
await check(topLevel({ crossOriginOpenerPolicy: false }), {
"cross-origin-opener-policy": null,
});
});
it("allows Cross-Origin-Resource-Policy middleware to be enabled with its default", async () => {
await check(topLevel({ crossOriginResourcePolicy: true }), {
"cross-origin-resource-policy": "same-origin",
});
});
it("allows Cross-Origin-Resource-Policy middleware to be enabled with custom arguments", async () => {
await check(
topLevel({ crossOriginResourcePolicy: { policy: "same-site" } }),
{
"cross-origin-resource-policy": "same-site",
},
);
});
it("allows Cross-Origin-Resource-Policy middleware to be explicitly disabled", async () => {
await check(topLevel({ crossOriginResourcePolicy: false }), {
"cross-origin-resource-policy": null,
});
});
it("allows Origin-Agent-Cluster middleware to be enabled", async () => {
await check(topLevel({ originAgentCluster: true }), {
"origin-agent-cluster": "?1",
});
});
it("allows Origin-Agent-Cluster middleware to be explicitly disabled", async () => {
await check(topLevel({ originAgentCluster: false }), {
"origin-agent-cluster": null,
});
});
it("properly handles a middleware calling `next()` with an error", async () => {
const app = connect()
.use(
topLevel({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'", () => "bad;value"],
},
},
}),
)
.use(
(
err: Error,
_req: IncomingMessage,
res: ServerResponse,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_next: () => void,
) => {
res.statusCode = 500;
res.setHeader("Content-Type", "application/json");
res.end(JSON.stringify({ message: err.message }));
},
);
await supertest(app).get("/").expect(500, {
message:
'Content-Security-Policy received an invalid directive value for "default-src"',
});
});
describe("warnings", () => {
const mockWarn = (t: TestContext) =>
t.mock.method(console, "warn", () => {});
const assertWarns = (
{ mock }: Mock<() => unknown>,
message: string,
): void => {
assert.equal(mock.callCount(), 1);
assert.deepEqual(mock.calls[0]?.arguments, [message]);
};
it("logs a warning when passing options to xPoweredBy", (t) => {
const warn = mockWarn(t);
topLevel({ xPoweredBy: { setTo: "deprecated option" } as any });
assertWarns(
warn,
"X-Powered-By does not take options. Remove the property to silence this warning.",
);
});
it("logs a warning when passing options to xDownloadOptions", (t) => {
const warn = mockWarn(t);
topLevel({ xDownloadOptions: { option: "foo" } as any });
assertWarns(
warn,
"X-Download-Options does not take options. Remove the property to silence this warning.",
);
});
it("logs a warning when passing options to originAgentCluster", (t) => {
const warn = mockWarn(t);
topLevel({ originAgentCluster: { option: "foo" } as any });
assertWarns(
warn,
"Origin-Agent-Cluster does not take options. Remove the property to silence this warning.",
);
});
it("logs a warning when passing options to xContentTypeOptions", (t) => {
const warn = mockWarn(t);
topLevel({ xContentTypeOptions: { option: "foo" } as any });
assertWarns(
warn,
"X-Content-Type-Options does not take options. Remove the property to silence this warning.",
);
});
it("logs a warning when passing options to xXssProtection", (t) => {
const warn = mockWarn(t);
topLevel({ xXssProtection: { setOnOldIe: true } as any });
assertWarns(
warn,
"X-XSS-Protection does not take options. Remove the property to silence this warning.",
);
});
});
it("exposes standalone middleware", () => {
assert.strictEqual(
helmet.contentSecurityPolicy.name,
contentSecurityPolicy.name,
);
assert.strictEqual(
helmet.contentSecurityPolicy.name,
"contentSecurityPolicy",
);
assert.strictEqual(
helmet.crossOriginEmbedderPolicy.name,
crossOriginEmbedderPolicy.name,
);
assert.strictEqual(
helmet.crossOriginEmbedderPolicy.name,
"crossOriginEmbedderPolicy",
);
assert.strictEqual(
helmet.crossOriginOpenerPolicy.name,
crossOriginOpenerPolicy.name,
);
assert.strictEqual(
helmet.crossOriginOpenerPolicy.name,
"crossOriginOpenerPolicy",
);
assert.strictEqual(
helmet.crossOriginResourcePolicy.name,
crossOriginResourcePolicy.name,
);
assert.strictEqual(
helmet.crossOriginResourcePolicy.name,
"crossOriginResourcePolicy",
);
assert.strictEqual(helmet.originAgentCluster.name, originAgentCluster.name);
assert.strictEqual(helmet.originAgentCluster.name, "originAgentCluster");
assert.strictEqual(helmet.referrerPolicy.name, referrerPolicy.name);
assert.strictEqual(helmet.referrerPolicy.name, "referrerPolicy");
assert.strictEqual(
helmet.strictTransportSecurity.name,
strictTransportSecurity.name,
);
assert.strictEqual(
helmet.strictTransportSecurity.name,
"strictTransportSecurity",
);
assert.strictEqual(
helmet.xContentTypeOptions.name,
xContentTypeOptions.name,
);
assert.strictEqual(helmet.xContentTypeOptions.name, "xContentTypeOptions");
assert.strictEqual(
helmet.xDnsPrefetchControl.name,
xDnsPrefetchControl.name,
);
assert.strictEqual(helmet.xDnsPrefetchControl.name, "xDnsPrefetchControl");
assert.strictEqual(helmet.xDownloadOptions.name, xDownloadOptions.name);
assert.strictEqual(helmet.xDownloadOptions.name, "xDownloadOptions");
assert.strictEqual(helmet.xFrameOptions.name, xFrameOptions.name);
assert.strictEqual(helmet.xFrameOptions.name, "xFrameOptions");
assert.strictEqual(
helmet.xPermittedCrossDomainPolicies.name,
xPermittedCrossDomainPolicies.name,
);
assert.strictEqual(
helmet.xPermittedCrossDomainPolicies.name,
"xPermittedCrossDomainPolicies",
);
assert.strictEqual(helmet.xPoweredBy.name, xPoweredBy.name);
assert.strictEqual(helmet.xPoweredBy.name, "xPoweredBy");
assert.strictEqual(helmet.xXssProtection.name, xXssProtection.name);
assert.strictEqual(helmet.xXssProtection.name, "xXssProtection");
});
it("exposes legacy header options", async () => {
await check(topLevel({ hsts: { maxAge: 123 } }), {
"strict-transport-security": "max-age=123; includeSubDomains",
});
await check(topLevel({ noSniff: false }), {
"x-content-type-options": null,
});
await check(topLevel({ dnsPrefetchControl: { allow: true } }), {
"x-dns-prefetch-control": "on",
});
await check(topLevel({ ieNoOpen: false }), {
"x-download-options": null,
});
await check(topLevel({ frameguard: { action: "deny" } }), {
"x-frame-options": "DENY",
});
await check(
topLevel({
permittedCrossDomainPolicies: { permittedPolicies: "by-content-type" },
}),
{
"x-permitted-cross-domain-policies": "by-content-type",
},
);
await check(topLevel({ hidePoweredBy: false }), {
"x-powered-by": "Helmet test",
});
await check(topLevel({ xssFilter: false }), {
"x-xss-protection": null,
});
});
it("errors with conflicting header options (legacy + new)", () => {
assert.throws(() =>
topLevel({ strictTransportSecurity: true, hsts: true } as any),
);
assert.throws(() =>
topLevel({ xContentTypeOptions: true, noSniff: true } as any),
);
assert.throws(() =>
topLevel({ xDnsPrefetchControl: true, dnsPrefetchControl: true } as any),
);
assert.throws(() =>
topLevel({ xDownloadOptions: true, ieNoOpen: true } as any),
);
assert.throws(() =>
topLevel({ xFrameOptions: true, frameguard: true } as any),
);
assert.throws(() =>
topLevel({
xPermittedCrossDomainPolicies: true,
permittedCrossDomainPolicies: true,
} as any),
);
assert.throws(() =>
topLevel({ xPoweredBy: true, hidePoweredBy: true } as any),
);
assert.throws(() =>
topLevel({ xXssProtection: true, xssFilter: true } as any),
);
});
it("exposes standalone middleware with legacy aliases", () => {
assert.strictEqual(helmet.hsts.name, strictTransportSecurity.name);
assert.strictEqual(
helmet.dnsPrefetchControl.name,
xDnsPrefetchControl.name,
);
assert.strictEqual(helmet.ieNoOpen.name, xDownloadOptions.name);
assert.strictEqual(helmet.frameguard.name, xFrameOptions.name);
assert.strictEqual(helmet.noSniff.name, xContentTypeOptions.name);
assert.strictEqual(helmet.hidePoweredBy.name, xPoweredBy.name);
assert.strictEqual(
helmet.permittedCrossDomainPolicies.name,
xPermittedCrossDomainPolicies.name,
);
assert.strictEqual(helmet.xssFilter.name, xXssProtection.name);
});
});
================================================
FILE: test/origin-agent-cluster.test.ts
================================================
import { describe, it } from "node:test";
import originAgentCluster from "../middlewares/origin-agent-cluster";
import { check } from "./helpers";
describe("Origin-Agent-Cluster middleware", () => {
it('sets "Origin-Agent-Cluster: ?1"', async () => {
await check(originAgentCluster(), {
"origin-agent-cluster": "?1",
});
});
});
================================================
FILE: test/project-setups/.gitignore
================================================
node_modules/
================================================
FILE: test/project-setups/javascript-commonjs/check.js
================================================
const connect = require("connect");
const supertest = require("supertest");
const helmet = require("helmet");
const handler = (_, res) => res.end("Hello world");
async function testTopLevel() {
const app = connect().use(helmet()).use(handler);
await supertest(app)
.get("/")
.expect(200, "Hello world")
.expect("x-download-options", "noopen");
}
async function testMiddleware() {
const app = connect().use(helmet.frameguard()).use(handler);
await supertest(app)
.get("/")
.expect(200, "Hello world")
.expect("x-frame-options", "SAMEORIGIN");
}
async function main() {
await testTopLevel();
await testMiddleware();
}
main().catch((err) => {
console.error(err);
process.exit(1);
});
================================================
FILE: test/project-setups/javascript-commonjs/package.json
================================================
{
"private": true,
"type": "commonjs",
"scripts": {
"helmet:test": "node check.js"
}
}
================================================
FILE: test/project-setups/javascript-commonjs-default-member/check.js
================================================
const connect = require("connect");
const supertest = require("supertest");
const { default: helmet, frameguard } = require("helmet");
const handler = (_, res) => res.end("Hello world");
async function testTopLevel() {
const app = connect().use(helmet()).use(handler);
await supertest(app)
.get("/")
.expect(200, "Hello world")
.expect("x-download-options", "noopen");
}
async function testMiddleware() {
const app = connect().use(frameguard()).use(handler);
await supertest(app)
.get("/")
.expect(200, "Hello world")
.expect("x-frame-options", "SAMEORIGIN");
}
async function main() {
await testTopLevel();
await testMiddleware();
}
main().catch((err) => {
console.error(err);
process.exit(1);
});
================================================
FILE: test/project-setups/javascript-commonjs-default-member/package.json
================================================
{
"private": true,
"type": "commonjs",
"scripts": {
"helmet:test": "node check.js"
}
}
================================================
FILE: test/project-setups/javascript-esm/check.js
================================================
import connect from "connect";
import helmet, { frameguard } from "helmet";
import supertest from "supertest";
const handler = (_, res) => res.end("Hello world");
async function testTopLevel() {
const app = connect().use(helmet()).use(handler);
await supertest(app)
.get("/")
.expect(200, "Hello world")
.expect("x-download-options", "noopen");
}
async function testImportedMiddleware() {
const app = connect().use(frameguard()).use(handler);
await supertest(app)
.get("/")
.expect(200, "Hello world")
.expect("x-frame-options", "SAMEORIGIN");
}
async function testAttachedMiddleware() {
const app = connect().use(helmet.frameguard()).use(handler);
await supertest(app)
.get("/")
.expect(200, "Hello world")
.expect("x-frame-options", "SAMEORIGIN");
}
async function main() {
await testTopLevel();
await testImportedMiddleware();
await testAttachedMiddleware();
}
main().catch((err) => {
console.error(err);
process.exit(1);
});
================================================
FILE: test/project-setups/javascript-esm/package.json
================================================
{
"private": true,
"type": "module",
"scripts": {
"helmet:test": "node check.js"
}
}
================================================
FILE: test/project-setups/typescript-commonjs/check.ts
================================================
import connect from "connect";
import helmet, { frameguard } from "helmet";
import type { IncomingMessage, ServerResponse } from "node:http";
import supertest from "supertest";
const handler = (_: IncomingMessage, res: ServerResponse) => {
res.end("Hello world");
};
async function testTopLevel() {
const app = connect().use(helmet()).use(handler);
await supertest(app)
.get("/")
.expect(200, "Hello world")
.expect("x-download-options", "noopen");
}
async function testImportedMiddleware() {
const app = connect().use(frameguard()).use(handler);
await supertest(app)
.get("/")
.expect(200, "Hello world")
.expect("x-frame-options", "SAMEORIGIN");
}
async function testAttachedMiddleware() {
const app = connect().use(helmet.frameguard()).use(handler);
await supertest(app)
.get("/")
.expect(200, "Hello world")
.expect("x-frame-options", "SAMEORIGIN");
}
async function main() {
await testTopLevel();
await testImportedMiddleware();
await testAttachedMiddleware();
}
main().catch((err) => {
console.error(err);
process.exit(1);
});
================================================
FILE: test/project-setups/typescript-commonjs/package.json
================================================
{
"private": true,
"type": "commonjs",
"scripts": {
"helmet:test": "tsx check.ts"
}
}
================================================
FILE: test/project-setups/typescript-commonjs/tsconfig.json
================================================
{
"compilerOptions": {
"module": "commonjs",
"moduleResolution": "node",
"esModuleInterop": true
}
}
================================================
FILE: test/project-setups/typescript-commonjs-nodenext-moduleResolution/check.ts
================================================
import connect from "connect";
import helmet, { frameguard } from "helmet";
import type { IncomingMessage, ServerResponse } from "node:http";
import supertest from "supertest";
const handler = (_: IncomingMessage, res: ServerResponse) => {
res.end("Hello world");
};
async function testTopLevel() {
const app = connect().use(helmet()).use(handler);
await supertest(app)
.get("/")
.expect(200, "Hello world")
.expect("x-download-options", "noopen");
}
async function testImportedMiddleware() {
const app = connect().use(frameguard()).use(handler);
await supertest(app)
.get("/")
.expect(200, "Hello world")
.expect("x-frame-options", "SAMEORIGIN");
}
async function testAttachedMiddleware() {
const app = connect().use(helmet.frameguard()).use(handler);
await supertest(app)
.get("/")
.expect(200, "Hello world")
.expect("x-frame-options", "SAMEORIGIN");
}
async function main() {
await testTopLevel();
await testImportedMiddleware();
await testAttachedMiddleware();
}
main().catch((err) => {
console.error(err);
process.exit(1);
});
================================================
FILE: test/project-setups/typescript-commonjs-nodenext-moduleResolution/package.json
================================================
{
"private": true,
"type": "commonjs",
"scripts": {
"helmet:test": "tsx check.ts"
}
}
================================================
FILE: test/project-setups/typescript-commonjs-nodenext-moduleResolution/tsconfig.json
================================================
{
"compilerOptions": {
"module": "commonjs",
"moduleResolution": "nodenext",
"esModuleInterop": true
}
}
================================================
FILE: test/project-setups/typescript-esnext/check.ts
================================================
import connect from "connect";
import helmet, { frameguard } from "helmet";
import type { IncomingMessage, ServerResponse } from "node:http";
import supertest from "supertest";
const handler = (_: IncomingMessage, res: ServerResponse) => {
res.end("Hello world");
};
async function testTopLevel() {
const app = connect().use(helmet()).use(handler);
await supertest(app)
.get("/")
.expect(200, "Hello world")
.expect("x-download-options", "noopen");
}
async function testImportedMiddleware() {
const app = connect().use(frameguard()).use(handler);
await supertest(app)
.get("/")
.expect(200, "Hello world")
.expect("x-frame-options", "SAMEORIGIN");
}
async function testAttachedMiddleware() {
const app = connect().use(helmet.frameguard()).use(handler);
await supertest(app)
.get("/")
.expect(200, "Hello world")
.expect("x-frame-options", "SAMEORIGIN");
}
async function main() {
await testTopLevel();
await testImportedMiddleware();
await testAttachedMiddleware();
}
main().catch((err) => {
console.error(err);
process.exit(1);
});
================================================
FILE: test/project-setups/typescript-esnext/package.json
================================================
{
"private": true,
"type": "module",
"scripts": {
"helmet:test": "tsx check.ts"
}
}
================================================
FILE: test/project-setups/typescript-esnext/tsconfig.json
================================================
{
"compilerOptions": {
"module": "esnext",
"moduleResolution": "node"
}
}
================================================
FILE: test/project-setups/typescript-nodenext-commonjs/check.ts
================================================
import connect from "connect";
import helmet, { frameguard } from "helmet";
import type { IncomingMessage, ServerResponse } from "node:http";
import supertest from "supertest";
const handler = (_: IncomingMessage, res: ServerResponse) => {
res.end("Hello world");
};
async function testTopLevel() {
const app = connect().use(helmet()).use(handler);
await supertest(app)
.get("/")
.expect(200, "Hello world")
.expect("x-download-options", "noopen");
}
async function testImportedMiddleware() {
const app = connect().use(frameguard()).use(handler);
await supertest(app)
.get("/")
.expect(200, "Hello world")
.expect("x-frame-options", "SAMEORIGIN");
}
async function testAttachedMiddleware() {
const app = connect().use(helmet.frameguard()).use(handler);
await supertest(app)
.get("/")
.expect(200, "Hello world")
.expect("x-frame-options", "SAMEORIGIN");
}
async function main() {
await testTopLevel();
await testImportedMiddleware();
await testAttachedMiddleware();
}
main().catch((err) => {
console.error(err);
process.exit(1);
});
================================================
FILE: test/project-setups/typescript-nodenext-commonjs/package.json
================================================
{
"private": true,
"type": "commonjs",
"scripts": {
"helmet:test": "tsx check.ts"
}
}
================================================
FILE: test/project-setups/typescript-nodenext-commonjs/tsconfig.json
================================================
{
"compilerOptions": {
"module": "nodenext",
"moduleResolution": "nodenext"
}
}
================================================
FILE: test/project-setups/typescript-nodenext-esm/check.ts
================================================
import connect from "connect";
import helmet, { frameguard } from "helmet";
import type { IncomingMessage, ServerResponse } from "node:http";
import supertest from "supertest";
const handler = (_: IncomingMessage, res: ServerResponse) => {
res.end("Hello world");
};
async function testTopLevel() {
const app = connect().use(helmet()).use(handler);
await supertest(app)
.get("/")
.expect(200, "Hello world")
.expect("x-download-options", "noopen");
}
async function testImportedMiddleware() {
const app = connect().use(frameguard()).use(handler);
await supertest(app)
.get("/")
.expect(200, "Hello world")
.expect("x-frame-options", "SAMEORIGIN");
}
async function testAttachedMiddleware() {
const app = connect().use(helmet.frameguard()).use(handler);
await supertest(app)
.get("/")
.expect(200, "Hello world")
.expect("x-frame-options", "SAMEORIGIN");
}
async function main() {
await testTopLevel();
await testImportedMiddleware();
await testAttachedMiddleware();
}
main().catch((err) => {
console.error(err);
process.exit(1);
});
================================================
FILE: test/project-setups/typescript-nodenext-esm/package.json
================================================
{
"private": true,
"type": "module",
"scripts": {
"helmet:test": "tsx check.ts"
}
}
================================================
FILE: test/project-setups/typescript-nodenext-esm/tsconfig.json
================================================
{
"compilerOptions": {
"module": "nodenext",
"moduleResolution": "nodenext"
}
}
================================================
FILE: test/project-setups.test.ts
================================================
import * as childProcess from "node:child_process";
import * as fs from "node:fs";
import * as path from "node:path";
import test from "node:test";
import { fileURLToPath } from "node:url";
import { promisify } from "node:util";
import { npm } from "../build/helpers.js";
const exec = promisify(childProcess.exec);
const projectSetupsFolder = fileURLToPath(
new URL("./project-setups", import.meta.url),
);
const projectSetups = fs
.readdirSync(projectSetupsFolder, { withFileTypes: true })
.filter((dirent) => dirent.isDirectory())
.map((dirent) => dirent.name);
async function buildHelmet(): Promise<string> {
// Unfortunately, we can't import `buildAndPack` directly.
// Run it and get the last line: the tarball path.
const { stdout } = await exec("npm run build");
const lines = stdout.trim().split(/\r?\n/g);
const result = lines[lines.length - 1]?.trim();
if (!result) {
throw new Error("Couldn't parse tarball path from build output");
}
return result;
}
let helmetTarballPromise: undefined | Promise<string>;
async function getHelmetTarballPath(): Promise<string> {
if (!helmetTarballPromise) {
helmetTarballPromise = buildHelmet();
}
return helmetTarballPromise;
}
for (const projectSetupName of projectSetups) {
test(`${projectSetupName} project setup`, { timeout: 60_000 }, async () => {
const projectFolder = path.join(projectSetupsFolder, projectSetupName);
const nodeModulesFolder = path.join(projectFolder, "node_modules");
await fs.promises.rm(nodeModulesFolder, { recursive: true, force: true });
await npm(
["install", "--no-save", "--no-audit", await getHelmetTarballPath()],
{
cwd: projectFolder,
},
);
await npm(["run", "helmet:test"], { cwd: projectFolder });
});
}
================================================
FILE: test/referrer-policy.test.ts
================================================
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import referrerPolicy from "../middlewares/referrer-policy";
import { check } from "./helpers";
describe("Referrer-Policy middleware", () => {
it("sets header to no-referrer when passed no policy", async () => {
await check(referrerPolicy(), {
"referrer-policy": "no-referrer",
});
await check(referrerPolicy({}), {
"referrer-policy": "no-referrer",
});
await check(referrerPolicy(Object.create(null)), {
"referrer-policy": "no-referrer",
});
await check(referrerPolicy({ policy: undefined }), {
"referrer-policy": "no-referrer",
});
});
(
[
"no-referrer",
"no-referrer-when-downgrade",
"same-origin",
"origin",
"strict-origin",
"origin-when-cross-origin",
"strict-origin-when-cross-origin",
"unsafe-url",
"",
] as const
).forEach((policy) => {
it(`can set the header to "${policy}" by specifying it as a string`, async () => {
await check(referrerPolicy({ policy }), {
"referrer-policy": policy,
});
});
it(`can set the header to "${policy}" by specifying it as an array string`, async () => {
await check(referrerPolicy({ policy: [policy] }), {
"referrer-policy": policy,
});
});
});
it("can set an array with multiple values", async () => {
await check(referrerPolicy({ policy: ["origin", "unsafe-url"] }), {
"referrer-policy": "origin,unsafe-url",
});
});
it("fails with a bad policy", () => {
const invalidValues = ["foo", "sameorigin", "ORIGIN", 123, false, null, {}];
for (const policy of invalidValues) {
assert.throws(() => referrerPolicy({ policy: policy as any }));
}
});
it("fails with an empty array", () => {
assert.throws(() => referrerPolicy({ policy: [] }));
});
it("fails with duplicate values", () => {
assert.throws(() => referrerPolicy({ policy: ["origin", "origin"] }));
assert.throws(() =>
referrerPolicy({ policy: ["same-origin", "origin", "same-origin"] }),
);
});
});
================================================
FILE: test/source-files.test.ts
================================================
import * as childProcess from "node:child_process";
import * as fs from "node:fs/promises";
import * as path from "node:path";
import { describe, it } from "node:test";
import { fileURLToPath } from "node:url";
import { promisify } from "node:util";
const EXTNAMES_THAT_DONT_HAVE_TO_BE_ASCII: ReadonlySet<string> = new Set([
".md",
]);
const NEWLINE = "\n".charCodeAt(0);
const SPACE = " ".charCodeAt(0);
const TILDE = "~".charCodeAt(0);
const exec = promisify(childProcess.exec);
const filename = fileURLToPath(import.meta.url);
const root = path.resolve(path.dirname(filename), "..");
describe("source files", () => {
it('only has "normal" ASCII characters in the source files', async () => {
const sourceFiles = await getSourceFiles();
for (const { path, contents } of sourceFiles) {
const abnormalByteIndex = contents.findIndex(
(byte) => !isNormalAsciiByte(byte),
);
if (abnormalByteIndex !== -1) {
throw new Error(
`${path} must only contain "normal" ASCII characters but contained abnormal byte at ${abnormalByteIndex}`,
);
}
}
});
});
const getSourceFiles = async (): Promise<
Iterable<{ path: string; contents: Uint8Array }>
> => {
const paths = await getSourceFilePaths();
return Promise.all(
paths.map(async (path) => ({
path,
contents: await fs.readFile(path),
})),
);
};
const getSourceFilePaths = async (): Promise<Array<string>> =>
(await exec("git ls-files", { cwd: root })).stdout
.split(/\r?\n/g)
.filter(
(file) => !EXTNAMES_THAT_DONT_HAVE_TO_BE_ASCII.has(path.extname(file)),
)
.filter(Boolean)
.map((line) => path.resolve(root, line));
const isNormalAsciiByte = (byte: number): boolean =>
byte === NEWLINE || (byte >= SPACE && byte <= TILDE);
================================================
FILE: test/strict-transport-security.test.ts
================================================
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import strictTransportSecurity from "../middlewares/strict-transport-security";
import { check } from "./helpers";
describe("Strict-Transport-Security middleware", () => {
it('by default, sets max-age to 365 days and adds "includeSubDomains"', async () => {
assert.equal(31536000, 365 * 24 * 60 * 60);
const expectedHeaders = {
"strict-transport-security": "max-age=31536000; includeSubDomains",
};
await check(strictTransportSecurity(), expectedHeaders);
await check(strictTransportSecurity({}), expectedHeaders);
await check(strictTransportSecurity(Object.create(null)), expectedHeaders);
await check(
strictTransportSecurity({ maxAge: undefined }),
expectedHeaders,
);
await check(
strictTransportSecurity({ includeSubDomains: undefined }),
expectedHeaders,
);
});
it("sets the max-age to a non-negative integer", async () => {
await check(strictTransportSecurity({ maxAge: 1234 }), {
"strict-transport-security": "max-age=1234; includeSubDomains",
});
await check(strictTransportSecurity({ maxAge: 0 }), {
"strict-transport-security": "max-age=0; includeSubDomains",
});
await check(strictTransp
gitextract_6o9fnhsw/ ├── .gitattributes ├── .github/ │ ├── dependabot.yml │ └── workflows/ │ └── nodejs.yml ├── .gitignore ├── .prettierignore ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md ├── build/ │ ├── build-package.ts │ └── helpers.ts ├── eslint.config.js ├── index.ts ├── middlewares/ │ ├── content-security-policy/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── index.ts │ │ └── package-overrides.json │ ├── cross-origin-embedder-policy/ │ │ └── index.ts │ ├── cross-origin-opener-policy/ │ │ └── index.ts │ ├── cross-origin-resource-policy/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── index.ts │ │ └── package-overrides.json │ ├── origin-agent-cluster/ │ │ └── index.ts │ ├── referrer-policy/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── index.ts │ │ └── package-overrides.json │ ├── strict-transport-security/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── index.ts │ │ └── package-overrides.json │ ├── x-content-type-options/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── index.ts │ │ └── package-overrides.json │ ├── x-dns-prefetch-control/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── index.ts │ │ └── package-overrides.json │ ├── x-download-options/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── index.ts │ │ └── package-overrides.json │ ├── x-frame-options/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── index.ts │ │ └── package-overrides.json │ ├── x-permitted-cross-domain-policies/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── index.ts │ │ └── package-overrides.json │ ├── x-powered-by/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── index.ts │ │ └── package-overrides.json │ └── x-xss-protection/ │ ├── CHANGELOG.md │ ├── README.md │ ├── index.ts │ └── package-overrides.json ├── package.json ├── test/ │ ├── content-security-policy.test.ts │ ├── cross-origin-embedder-policy.test.ts │ ├── cross-origin-opener-policy.test.ts │ ├── cross-origin-resource-policy.test.ts │ ├── helpers.ts │ ├── index.test.ts │ ├── origin-agent-cluster.test.ts │ ├── project-setups/ │ │ ├── .gitignore │ │ ├── javascript-commonjs/ │ │ │ ├── check.js │ │ │ └── package.json │ │ ├── javascript-commonjs-default-member/ │ │ │ ├── check.js │ │ │ └── package.json │ │ ├── javascript-esm/ │ │ │ ├── check.js │ │ │ └── package.json │ │ ├── typescript-commonjs/ │ │ │ ├── check.ts │ │ │ ├── package.json │ │ │ └── tsconfig.json │ │ ├── typescript-commonjs-nodenext-moduleResolution/ │ │ │ ├── check.ts │ │ │ ├── package.json │ │ │ └── tsconfig.json │ │ ├── typescript-esnext/ │ │ │ ├── check.ts │ │ │ ├── package.json │ │ │ └── tsconfig.json │ │ ├── typescript-nodenext-commonjs/ │ │ │ ├── check.ts │ │ │ ├── package.json │ │ │ └── tsconfig.json │ │ └── typescript-nodenext-esm/ │ │ ├── check.ts │ │ ├── package.json │ │ └── tsconfig.json │ ├── project-setups.test.ts │ ├── referrer-policy.test.ts │ ├── source-files.test.ts │ ├── strict-transport-security.test.ts │ ├── x-content-type-options.test.ts │ ├── x-dns-prefetch-control.test.ts │ ├── x-download-options.test.ts │ ├── x-frame-options.test.ts │ ├── x-permitted-cross-domain-policies.test.ts │ ├── x-powered-by.test.ts │ └── x-xss-protection.test.ts └── tsconfig.json
SYMBOL INDEX (100 symbols across 28 files)
FILE: build/build-package.ts
constant PRETTIER_PREPACK_CRUSH_OPTIONS (line 21) | const PRETTIER_PREPACK_CRUSH_OPTIONS: prettier.Options = {
function buildAndPack (line 36) | async function buildAndPack(
function temporaryDirectory (line 87) | function temporaryDirectory(): Promise<string> {
function buildCjs (line 91) | async function buildCjs({
function buildMjs (line 118) | async function buildMjs({
function rollupForJs (line 139) | function rollupForJs({
function buildTypes (line 154) | async function buildTypes({
function buildPackageJson (line 192) | async function buildPackageJson({
function readJsonObject (line 266) | async function readJsonObject(
function copyStaticFiles (line 276) | async function copyStaticFiles({
function prePackCrush (line 291) | async function prePackCrush(distDir: string): Promise<void> {
function pack (line 319) | async function pack(distDir: string): Promise<string> {
function postPackCrush (line 335) | async function postPackCrush(originalTarGz: string): Promise<string> {
FILE: index.ts
type HelmetOptions (line 35) | type HelmetOptions = {
type MiddlewareFunction (line 97) | type MiddlewareFunction = (
type Helmet (line 103) | interface Helmet {
function getMiddlewareFunctionsFromOptions (line 138) | function getMiddlewareFunctionsFromOptions(
FILE: middlewares/content-security-policy/index.ts
type ContentSecurityPolicyDirectiveValueFunction (line 3) | type ContentSecurityPolicyDirectiveValueFunction = (
type ContentSecurityPolicyDirectiveValue (line 8) | type ContentSecurityPolicyDirectiveValue =
type ContentSecurityPolicyOptions (line 12) | interface ContentSecurityPolicyOptions {
type NormalizedDirectives (line 23) | type NormalizedDirectives = Map<
type ContentSecurityPolicy (line 28) | interface ContentSecurityPolicy {
constant SHOULD_BE_QUOTED (line 42) | const SHOULD_BE_QUOTED: ReadonlySet<string> = new Set([
function normalizeDirectives (line 106) | function normalizeDirectives(
function getHeaderValue (line 217) | function getHeaderValue(
FILE: middlewares/cross-origin-embedder-policy/index.ts
type CrossOriginEmbedderPolicyOptions (line 3) | interface CrossOriginEmbedderPolicyOptions {
constant ALLOWED_POLICIES (line 7) | const ALLOWED_POLICIES = new Set([
function getHeaderValueFromOptions (line 13) | function getHeaderValueFromOptions({
function crossOriginEmbedderPolicy (line 27) | function crossOriginEmbedderPolicy(
FILE: middlewares/cross-origin-opener-policy/index.ts
type CrossOriginOpenerPolicyOptions (line 3) | interface CrossOriginOpenerPolicyOptions {
constant ALLOWED_POLICIES (line 11) | const ALLOWED_POLICIES = new Set([
function getHeaderValueFromOptions (line 18) | function getHeaderValueFromOptions({
function crossOriginOpenerPolicy (line 32) | function crossOriginOpenerPolicy(
FILE: middlewares/cross-origin-resource-policy/index.ts
type CrossOriginResourcePolicyOptions (line 3) | interface CrossOriginResourcePolicyOptions {
constant ALLOWED_POLICIES (line 7) | const ALLOWED_POLICIES = new Set(["same-origin", "same-site", "cross-ori...
function getHeaderValueFromOptions (line 9) | function getHeaderValueFromOptions({
function crossOriginResourcePolicy (line 23) | function crossOriginResourcePolicy(
FILE: middlewares/origin-agent-cluster/index.ts
function originAgentCluster (line 3) | function originAgentCluster() {
FILE: middlewares/referrer-policy/index.ts
type ReferrerPolicyToken (line 3) | type ReferrerPolicyToken =
type ReferrerPolicyOptions (line 14) | interface ReferrerPolicyOptions {
constant ALLOWED_TOKENS (line 18) | const ALLOWED_TOKENS = new Set<ReferrerPolicyToken>([
function getHeaderValueFromOptions (line 30) | function getHeaderValueFromOptions({
function referrerPolicy (line 60) | function referrerPolicy(options: Readonly<ReferrerPolicyOptions> = {}) {
FILE: middlewares/strict-transport-security/index.ts
constant DEFAULT_MAX_AGE (line 3) | const DEFAULT_MAX_AGE = 365 * 24 * 60 * 60;
type StrictTransportSecurityOptions (line 5) | interface StrictTransportSecurityOptions {
function parseMaxAge (line 11) | function parseMaxAge(value: number = DEFAULT_MAX_AGE): number {
function getHeaderValueFromOptions (line 23) | function getHeaderValueFromOptions(
function strictTransportSecurity (line 50) | function strictTransportSecurity(
FILE: middlewares/x-content-type-options/index.ts
function xContentTypeOptions (line 3) | function xContentTypeOptions() {
FILE: middlewares/x-dns-prefetch-control/index.ts
type XDnsPrefetchControlOptions (line 3) | interface XDnsPrefetchControlOptions {
function xDnsPrefetchControl (line 7) | function xDnsPrefetchControl(
FILE: middlewares/x-download-options/index.ts
function xDownloadOptions (line 3) | function xDownloadOptions() {
FILE: middlewares/x-frame-options/index.ts
type XFrameOptionsOptions (line 3) | interface XFrameOptionsOptions {
function getHeaderValueFromOptions (line 7) | function getHeaderValueFromOptions({
function xFrameOptions (line 26) | function xFrameOptions(options: Readonly<XFrameOptionsOptions> = {}) {
FILE: middlewares/x-permitted-cross-domain-policies/index.ts
type XPermittedCrossDomainPoliciesOptions (line 3) | interface XPermittedCrossDomainPoliciesOptions {
constant ALLOWED_PERMITTED_POLICIES (line 7) | const ALLOWED_PERMITTED_POLICIES = new Set([
function getHeaderValueFromOptions (line 14) | function getHeaderValueFromOptions({
function xPermittedCrossDomainPolicies (line 28) | function xPermittedCrossDomainPolicies(
FILE: middlewares/x-powered-by/index.ts
function xPoweredBy (line 3) | function xPoweredBy() {
FILE: middlewares/x-xss-protection/index.ts
function xXssProtection (line 3) | function xXssProtection() {
FILE: test/content-security-policy.test.ts
function checkCsp (line 31) | async function checkCsp({
FILE: test/helpers.ts
type MiddlewareFunction (line 6) | type MiddlewareFunction = (
function check (line 12) | async function check(
FILE: test/project-setups.test.ts
function buildHelmet (line 19) | async function buildHelmet(): Promise<string> {
function getHelmetTarballPath (line 32) | async function getHelmetTarballPath(): Promise<string> {
FILE: test/project-setups/javascript-commonjs-default-member/check.js
function testTopLevel (line 7) | async function testTopLevel() {
function testMiddleware (line 15) | async function testMiddleware() {
function main (line 23) | async function main() {
FILE: test/project-setups/javascript-commonjs/check.js
function testTopLevel (line 7) | async function testTopLevel() {
function testMiddleware (line 15) | async function testMiddleware() {
function main (line 23) | async function main() {
FILE: test/project-setups/javascript-esm/check.js
function testTopLevel (line 7) | async function testTopLevel() {
function testImportedMiddleware (line 15) | async function testImportedMiddleware() {
function testAttachedMiddleware (line 23) | async function testAttachedMiddleware() {
function main (line 31) | async function main() {
FILE: test/project-setups/typescript-commonjs-nodenext-moduleResolution/check.ts
function testTopLevel (line 10) | async function testTopLevel() {
function testImportedMiddleware (line 18) | async function testImportedMiddleware() {
function testAttachedMiddleware (line 26) | async function testAttachedMiddleware() {
function main (line 34) | async function main() {
FILE: test/project-setups/typescript-commonjs/check.ts
function testTopLevel (line 10) | async function testTopLevel() {
function testImportedMiddleware (line 18) | async function testImportedMiddleware() {
function testAttachedMiddleware (line 26) | async function testAttachedMiddleware() {
function main (line 34) | async function main() {
FILE: test/project-setups/typescript-esnext/check.ts
function testTopLevel (line 10) | async function testTopLevel() {
function testImportedMiddleware (line 18) | async function testImportedMiddleware() {
function testAttachedMiddleware (line 26) | async function testAttachedMiddleware() {
function main (line 34) | async function main() {
FILE: test/project-setups/typescript-nodenext-commonjs/check.ts
function testTopLevel (line 10) | async function testTopLevel() {
function testImportedMiddleware (line 18) | async function testImportedMiddleware() {
function testAttachedMiddleware (line 26) | async function testAttachedMiddleware() {
function main (line 34) | async function main() {
FILE: test/project-setups/typescript-nodenext-esm/check.ts
function testTopLevel (line 10) | async function testTopLevel() {
function testImportedMiddleware (line 18) | async function testImportedMiddleware() {
function testAttachedMiddleware (line 26) | async function testAttachedMiddleware() {
function main (line 34) | async function main() {
FILE: test/source-files.test.ts
constant EXTNAMES_THAT_DONT_HAVE_TO_BE_ASCII (line 8) | const EXTNAMES_THAT_DONT_HAVE_TO_BE_ASCII: ReadonlySet<string> = new Set([
constant NEWLINE (line 11) | const NEWLINE = "\n".charCodeAt(0);
constant SPACE (line 12) | const SPACE = " ".charCodeAt(0);
constant TILDE (line 13) | const TILDE = "~".charCodeAt(0);
Condensed preview — 104 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (212K chars).
[
{
"path": ".gitattributes",
"chars": 19,
"preview": "* text=auto eol=lf\n"
},
{
"path": ".github/dependabot.yml",
"chars": 119,
"preview": "version: 2\nupdates:\n - package-ecosystem: \"github-actions\"\n directory: \"/\"\n schedule:\n interval: \"monthly\"\n"
},
{
"path": ".github/workflows/nodejs.yml",
"chars": 574,
"preview": "name: Node.js CI\n\non: [push]\n\npermissions:\n contents: read\n\njobs:\n build:\n runs-on: ubuntu-latest\n\n strategy:\n "
},
{
"path": ".gitignore",
"chars": 39,
"preview": "/node_modules/\n/coverage/\n.eslintcache\n"
},
{
"path": ".prettierignore",
"chars": 11,
"preview": "/coverage/\n"
},
{
"path": "CHANGELOG.md",
"chars": 25647,
"preview": "# Changelog\n\n## Unreleased\n\n- `Cross-Origin-Opener-Policy`: support `noopener-allow-popups`. See [#522](https://github.c"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 5247,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participa"
},
{
"path": "CONTRIBUTING.md",
"chars": 1096,
"preview": "# Contributing to Helmet\n\nHelmet welcomes contributors! This guide should help you submit issues and pull requests.\n\n## "
},
{
"path": "LICENSE",
"chars": 1089,
"preview": "The MIT License\n\nCopyright (c) 2012-2026 Evan Hahn, Adam Baldwin\n\nPermission is hereby granted, free of charge, to any p"
},
{
"path": "README.md",
"chars": 19668,
"preview": "# Helmet\n\nHelmet helps secure Node/Express apps. It sets HTTP response headers such as `Content-Security-Policy` and `St"
},
{
"path": "SECURITY.md",
"chars": 607,
"preview": "# Security issue reporting & disclosure process\n\nPlease reach out if you think you've found a security issue.\n\nEmail Eva"
},
{
"path": "build/build-package.ts",
"chars": 10397,
"preview": "import rollupTypescript from \"@rollup/plugin-typescript\";\nimport zopfli from \"node-zopfli\";\nimport * as fsOriginal from "
},
{
"path": "build/helpers.ts",
"chars": 503,
"preview": "import * as childProcess from \"node:child_process\";\n\nexport const npm = (\n args: readonly string[],\n { cwd }: Readonly"
},
{
"path": "eslint.config.js",
"chars": 2141,
"preview": "import pluginJs from \"@eslint/js\";\nimport globals from \"globals\";\nimport tseslint from \"typescript-eslint\";\n\nexport defa"
},
{
"path": "index.ts",
"chars": 14084,
"preview": "import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport contentSecurityPolicy, {\n type ContentSecurity"
},
{
"path": "middlewares/content-security-policy/CHANGELOG.md",
"chars": 4229,
"preview": "# Changelog\n\n## 4.0.0 - 2024-06-01\n\n### Changed\n\n- **Breaking:** `useDefaults` option now defaults to `true`\n- **Breakin"
},
{
"path": "middlewares/content-security-policy/README.md",
"chars": 3621,
"preview": "# Content Security Policy middleware\n\nThe `Content-Security-Policy` header mitigates a large number of attacks, such as "
},
{
"path": "middlewares/content-security-policy/index.ts",
"chars": 8152,
"preview": "import type { IncomingMessage, ServerResponse } from \"node:http\";\n\ntype ContentSecurityPolicyDirectiveValueFunction = (\n"
},
{
"path": "middlewares/content-security-policy/package-overrides.json",
"chars": 445,
"preview": "{\n \"name\": \"helmet-csp\",\n \"author\": \"Adam Baldwin <adam@npmjs.com> (https://evilpacket.net)\",\n \"contributors\": [\n "
},
{
"path": "middlewares/cross-origin-embedder-policy/index.ts",
"chars": 1032,
"preview": "import type { IncomingMessage, ServerResponse } from \"node:http\";\n\nexport interface CrossOriginEmbedderPolicyOptions {\n "
},
{
"path": "middlewares/cross-origin-opener-policy/index.ts",
"chars": 1104,
"preview": "import type { IncomingMessage, ServerResponse } from \"node:http\";\n\nexport interface CrossOriginOpenerPolicyOptions {\n p"
},
{
"path": "middlewares/cross-origin-resource-policy/CHANGELOG.md",
"chars": 815,
"preview": "# Changelog\n\n## Unreleased\n\n### Changed\n\n- **Breaking:** increase TypeScript strictness around arguments. Only affects T"
},
{
"path": "middlewares/cross-origin-resource-policy/README.md",
"chars": 534,
"preview": "# Cross-Origin-Resource-Policy middleware\n\nThis middleware sets the `Cross-Origin-Resource-Policy` header. Read about it"
},
{
"path": "middlewares/cross-origin-resource-policy/index.ts",
"chars": 1012,
"preview": "import type { IncomingMessage, ServerResponse } from \"node:http\";\n\nexport interface CrossOriginResourcePolicyOptions {\n "
},
{
"path": "middlewares/cross-origin-resource-policy/package-overrides.json",
"chars": 324,
"preview": "{\n \"name\": \"cross-origin-resource-policy\",\n \"author\": \"Evan Hahn <me@evanhahn.com> (https://evanhahn.com)\",\n \"contrib"
},
{
"path": "middlewares/origin-agent-cluster/index.ts",
"chars": 337,
"preview": "import type { IncomingMessage, ServerResponse } from \"node:http\";\n\nfunction originAgentCluster() {\n return function ori"
},
{
"path": "middlewares/referrer-policy/CHANGELOG.md",
"chars": 766,
"preview": "# Changelog\n\n## Unreleased\n\n### Changed\n\n- **Breaking:** increase TypeScript strictness around arguments. Only affects T"
},
{
"path": "middlewares/referrer-policy/README.md",
"chars": 1106,
"preview": "# Referrer-Policy middleware\n\nThe [Referer HTTP header](https://en.wikipedia.org/wiki/HTTP_referer) is typically set by "
},
{
"path": "middlewares/referrer-policy/index.ts",
"chars": 1782,
"preview": "import type { IncomingMessage, ServerResponse } from \"node:http\";\n\ntype ReferrerPolicyToken =\n | \"no-referrer\"\n | \"no-"
},
{
"path": "middlewares/referrer-policy/package-overrides.json",
"chars": 375,
"preview": "{\n \"name\": \"referrer-policy\",\n \"author\": \"Evan Hahn <me@evanhahn.com> (https://evanhahn.com)\",\n \"contributors\": [],\n "
},
{
"path": "middlewares/strict-transport-security/CHANGELOG.md",
"chars": 1458,
"preview": "# Changelog\n\n## 3.0.0 - Unreleased\n\n### Added\n\n- TypeScript type definitions. See [#25](https://github.com/helmetjs/hsts"
},
{
"path": "middlewares/strict-transport-security/README.md",
"chars": 1859,
"preview": "# HTTP Strict Transport Security middleware\n\nThis middleware adds the `Strict-Transport-Security` header to the response"
},
{
"path": "middlewares/strict-transport-security/index.ts",
"chars": 1768,
"preview": "import type { IncomingMessage, ServerResponse } from \"node:http\";\n\nconst DEFAULT_MAX_AGE = 365 * 24 * 60 * 60;\n\nexport i"
},
{
"path": "middlewares/strict-transport-security/package-overrides.json",
"chars": 257,
"preview": "{\n \"name\": \"hsts\",\n \"description\": \"HTTP Strict Transport Security middleware\",\n \"version\": \"2.2.0\",\n \"keywords\": [\n"
},
{
"path": "middlewares/x-content-type-options/CHANGELOG.md",
"chars": 570,
"preview": "# Changelog\n\n## 2.0.0 - Unreleased\n\n### Removed\n\n- Dropped support for old Node versions. Node 10+ is now required\n\n## 1"
},
{
"path": "middlewares/x-content-type-options/README.md",
"chars": 1275,
"preview": "# X-Content-Type-Options middleware\n\nSome browsers will try to \"sniff\" mimetypes. For example, if my server serves _file"
},
{
"path": "middlewares/x-content-type-options/index.ts",
"chars": 341,
"preview": "import type { IncomingMessage, ServerResponse } from \"node:http\";\n\nfunction xContentTypeOptions() {\n return function xC"
},
{
"path": "middlewares/x-content-type-options/package-overrides.json",
"chars": 248,
"preview": "{\n \"name\": \"dont-sniff-mimetype\",\n \"description\": \"Middleware to prevent mimetype from being sniffed\",\n \"version\": \"1"
},
{
"path": "middlewares/x-dns-prefetch-control/CHANGELOG.md",
"chars": 627,
"preview": "# Changelog\n\n## Unreleased\n\n### Removed\n\n- Dropped support for old Node versions. Node 10+ is now required\n\n## 0.3.0 - 2"
},
{
"path": "middlewares/x-dns-prefetch-control/README.md",
"chars": 646,
"preview": "# X-DNS-Prefetch-Control middleware\n\nThis middleware lets you set the `X-DNS-Prefetch-Control` to control browsers' DNS "
},
{
"path": "middlewares/x-dns-prefetch-control/index.ts",
"chars": 525,
"preview": "import type { IncomingMessage, ServerResponse } from \"node:http\";\n\nexport interface XDnsPrefetchControlOptions {\n allow"
},
{
"path": "middlewares/x-dns-prefetch-control/package-overrides.json",
"chars": 336,
"preview": "{\n \"name\": \"dns-prefetch-control\",\n \"author\": \"Evan Hahn <me@evanhahn.com> (https://evanhahn.com)\",\n \"contributors\": "
},
{
"path": "middlewares/x-download-options/CHANGELOG.md",
"chars": 612,
"preview": "# Changelog\n\n## 2.0.0 - Unreleased\n\n- Dropped support for old Node versions. Node 10+ is now required\n\n## 1.1.1 - 2020-0"
},
{
"path": "middlewares/x-download-options/README.md",
"chars": 797,
"preview": "# X-Download-Options middleware\n\nThis middleware sets the `X-Download-Options` header to `noopen` to prevent Internet Ex"
},
{
"path": "middlewares/x-download-options/index.ts",
"chars": 333,
"preview": "import type { IncomingMessage, ServerResponse } from \"node:http\";\n\nfunction xDownloadOptions() {\n return function xDown"
},
{
"path": "middlewares/x-download-options/package-overrides.json",
"chars": 401,
"preview": "{\n \"name\": \"ienoopen\",\n \"contributors\": [\n \"Evan Hahn <me@evanhahn.com> (https://evanhahn.com)\",\n \"Nathan Shivel"
},
{
"path": "middlewares/x-frame-options/CHANGELOG.md",
"chars": 1112,
"preview": "# Changelog\n\n## Unreleased\n\n### Changed\n\n- **Breaking:** increase TypeScript strictness around arguments. Only affects T"
},
{
"path": "middlewares/x-frame-options/README.md",
"chars": 1106,
"preview": "# X-Frame-Options middleware\n\nThe `X-Frame-Options` HTTP header restricts who can put your site in a frame which can hel"
},
{
"path": "middlewares/x-frame-options/index.ts",
"chars": 981,
"preview": "import type { IncomingMessage, ServerResponse } from \"node:http\";\n\nexport interface XFrameOptionsOptions {\n action?: \"d"
},
{
"path": "middlewares/x-frame-options/package-overrides.json",
"chars": 225,
"preview": "{\n \"name\": \"frameguard\",\n \"description\": \"Middleware to set X-Frame-Options headers\",\n \"version\": \"4.0.0\",\n \"keyword"
},
{
"path": "middlewares/x-permitted-cross-domain-policies/CHANGELOG.md",
"chars": 734,
"preview": "# Changelog\n\n## Unreleased\n\n### Changed\n\n- **Breaking:** increase TypeScript strictness around arguments. Only affects T"
},
{
"path": "middlewares/x-permitted-cross-domain-policies/README.md",
"chars": 955,
"preview": "# X-Permitted-Cross-Domain-Policies middleware\n\nThe `X-Permitted-Cross-Domain-Policies` header tells some web clients (l"
},
{
"path": "middlewares/x-permitted-cross-domain-policies/index.ts",
"chars": 1125,
"preview": "import type { IncomingMessage, ServerResponse } from \"node:http\";\n\nexport interface XPermittedCrossDomainPoliciesOptions"
},
{
"path": "middlewares/x-permitted-cross-domain-policies/package-overrides.json",
"chars": 388,
"preview": "{\n \"name\": \"helmet-crossdomain\",\n \"author\": \"Evan Hahn <me@evanhahn.com> (https://evanhahn.com)\",\n \"contributors\": []"
},
{
"path": "middlewares/x-powered-by/CHANGELOG.md",
"chars": 781,
"preview": "# Changelog\n\n## 2.0.0 - Unreleased\n\n### Removed\n\n- Removed `setTo` option. See [this article](https://github.com/helmetj"
},
{
"path": "middlewares/x-powered-by/README.md",
"chars": 802,
"preview": "# X-Powered-By middleware\n\nSimple middleware to remove the `X-Powered-By` HTTP header if it's set.\n\nHackers can exploit "
},
{
"path": "middlewares/x-powered-by/index.ts",
"chars": 296,
"preview": "import type { IncomingMessage, ServerResponse } from \"node:http\";\n\nfunction xPoweredBy() {\n return function xPoweredByM"
},
{
"path": "middlewares/x-powered-by/package-overrides.json",
"chars": 361,
"preview": "{\n \"name\": \"hide-powered-by\",\n \"contributors\": [\n \"Evan Hahn <me@evanhahn.com> (https://evanhahn.com)\",\n \"Ameen "
},
{
"path": "middlewares/x-xss-protection/CHANGELOG.md",
"chars": 1211,
"preview": "# Changelog\n\n## 2.0.0 - 2020-08-02\n\n### Changed\n\n- XSS filtering is now disabled by default. See [#230](https://github.c"
},
{
"path": "middlewares/x-xss-protection/README.md",
"chars": 973,
"preview": "# X-XSS-Protection middleware\n\nThe `X-XSS-Protection` HTTP header aimed to offer a basic protection against cross-site s"
},
{
"path": "middlewares/x-xss-protection/index.ts",
"chars": 314,
"preview": "import type { IncomingMessage, ServerResponse } from \"node:http\";\n\nfunction xXssProtection() {\n return function xXssPro"
},
{
"path": "middlewares/x-xss-protection/package-overrides.json",
"chars": 227,
"preview": "{\n \"name\": \"x-xss-protection\",\n \"description\": \"Middleware to disable the X-XSS-Protection header\",\n \"version\": \"2.0."
},
{
"path": "package.json",
"chars": 1043,
"preview": "{\n \"private\": true,\n \"version\": \"8.1.0\",\n \"devDependencies\": {\n \"@eslint/js\": \"^10.0.1\",\n \"@rollup/plugin-types"
},
{
"path": "test/content-security-policy.test.ts",
"chars": 16924,
"preview": "import connect from \"connect\";\nimport assert from \"node:assert/strict\";\nimport { IncomingMessage, ServerResponse } from "
},
{
"path": "test/cross-origin-embedder-policy.test.ts",
"chars": 1569,
"preview": "import assert from \"node:assert/strict\";\nimport { describe, it } from \"node:test\";\nimport crossOriginEmbedderPolicy from"
},
{
"path": "test/cross-origin-opener-policy.test.ts",
"chars": 1538,
"preview": "import assert from \"node:assert/strict\";\nimport { describe, it } from \"node:test\";\nimport crossOriginOpenerPolicy from \""
},
{
"path": "test/cross-origin-resource-policy.test.ts",
"chars": 1511,
"preview": "import assert from \"node:assert/strict\";\nimport { describe, it } from \"node:test\";\nimport crossOriginResourcePolicy from"
},
{
"path": "test/helpers.ts",
"chars": 1143,
"preview": "import connect from \"connect\";\nimport assert from \"node:assert/strict\";\nimport type { IncomingMessage, ServerResponse } "
},
{
"path": "test/index.test.ts",
"chars": 14861,
"preview": "import connect from \"connect\";\nimport assert from \"node:assert/strict\";\nimport type { IncomingMessage, ServerResponse } "
},
{
"path": "test/origin-agent-cluster.test.ts",
"chars": 348,
"preview": "import { describe, it } from \"node:test\";\nimport originAgentCluster from \"../middlewares/origin-agent-cluster\";\nimport {"
},
{
"path": "test/project-setups/.gitignore",
"chars": 13,
"preview": "node_modules/"
},
{
"path": "test/project-setups/javascript-commonjs/check.js",
"chars": 726,
"preview": "const connect = require(\"connect\");\nconst supertest = require(\"supertest\");\nconst helmet = require(\"helmet\");\n\nconst han"
},
{
"path": "test/project-setups/javascript-commonjs/package.json",
"chars": 99,
"preview": "{\n \"private\": true,\n \"type\": \"commonjs\",\n \"scripts\": {\n \"helmet:test\": \"node check.js\"\n }\n}\n"
},
{
"path": "test/project-setups/javascript-commonjs-default-member/check.js",
"chars": 744,
"preview": "const connect = require(\"connect\");\nconst supertest = require(\"supertest\");\nconst { default: helmet, frameguard } = requ"
},
{
"path": "test/project-setups/javascript-commonjs-default-member/package.json",
"chars": 99,
"preview": "{\n \"private\": true,\n \"type\": \"commonjs\",\n \"scripts\": {\n \"helmet:test\": \"node check.js\"\n }\n}\n"
},
{
"path": "test/project-setups/javascript-esm/check.js",
"chars": 993,
"preview": "import connect from \"connect\";\nimport helmet, { frameguard } from \"helmet\";\nimport supertest from \"supertest\";\n\nconst ha"
},
{
"path": "test/project-setups/javascript-esm/package.json",
"chars": 97,
"preview": "{\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"helmet:test\": \"node check.js\"\n }\n}\n"
},
{
"path": "test/project-setups/typescript-commonjs/check.ts",
"chars": 1099,
"preview": "import connect from \"connect\";\nimport helmet, { frameguard } from \"helmet\";\nimport type { IncomingMessage, ServerRespons"
},
{
"path": "test/project-setups/typescript-commonjs/package.json",
"chars": 98,
"preview": "{\n \"private\": true,\n \"type\": \"commonjs\",\n \"scripts\": {\n \"helmet:test\": \"tsx check.ts\"\n }\n}\n"
},
{
"path": "test/project-setups/typescript-commonjs/tsconfig.json",
"chars": 117,
"preview": "{\n \"compilerOptions\": {\n \"module\": \"commonjs\",\n \"moduleResolution\": \"node\",\n \"esModuleInterop\": true\n }\n}\n"
},
{
"path": "test/project-setups/typescript-commonjs-nodenext-moduleResolution/check.ts",
"chars": 1099,
"preview": "import connect from \"connect\";\nimport helmet, { frameguard } from \"helmet\";\nimport type { IncomingMessage, ServerRespons"
},
{
"path": "test/project-setups/typescript-commonjs-nodenext-moduleResolution/package.json",
"chars": 98,
"preview": "{\n \"private\": true,\n \"type\": \"commonjs\",\n \"scripts\": {\n \"helmet:test\": \"tsx check.ts\"\n }\n}\n"
},
{
"path": "test/project-setups/typescript-commonjs-nodenext-moduleResolution/tsconfig.json",
"chars": 121,
"preview": "{\n \"compilerOptions\": {\n \"module\": \"commonjs\",\n \"moduleResolution\": \"nodenext\",\n \"esModuleInterop\": true\n }\n}"
},
{
"path": "test/project-setups/typescript-esnext/check.ts",
"chars": 1099,
"preview": "import connect from \"connect\";\nimport helmet, { frameguard } from \"helmet\";\nimport type { IncomingMessage, ServerRespons"
},
{
"path": "test/project-setups/typescript-esnext/package.json",
"chars": 96,
"preview": "{\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"helmet:test\": \"tsx check.ts\"\n }\n}\n"
},
{
"path": "test/project-setups/typescript-esnext/tsconfig.json",
"chars": 86,
"preview": "{\n \"compilerOptions\": {\n \"module\": \"esnext\",\n \"moduleResolution\": \"node\"\n }\n}\n"
},
{
"path": "test/project-setups/typescript-nodenext-commonjs/check.ts",
"chars": 1099,
"preview": "import connect from \"connect\";\nimport helmet, { frameguard } from \"helmet\";\nimport type { IncomingMessage, ServerRespons"
},
{
"path": "test/project-setups/typescript-nodenext-commonjs/package.json",
"chars": 98,
"preview": "{\n \"private\": true,\n \"type\": \"commonjs\",\n \"scripts\": {\n \"helmet:test\": \"tsx check.ts\"\n }\n}\n"
},
{
"path": "test/project-setups/typescript-nodenext-commonjs/tsconfig.json",
"chars": 92,
"preview": "{\n \"compilerOptions\": {\n \"module\": \"nodenext\",\n \"moduleResolution\": \"nodenext\"\n }\n}\n"
},
{
"path": "test/project-setups/typescript-nodenext-esm/check.ts",
"chars": 1099,
"preview": "import connect from \"connect\";\nimport helmet, { frameguard } from \"helmet\";\nimport type { IncomingMessage, ServerRespons"
},
{
"path": "test/project-setups/typescript-nodenext-esm/package.json",
"chars": 96,
"preview": "{\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"helmet:test\": \"tsx check.ts\"\n }\n}\n"
},
{
"path": "test/project-setups/typescript-nodenext-esm/tsconfig.json",
"chars": 92,
"preview": "{\n \"compilerOptions\": {\n \"module\": \"nodenext\",\n \"moduleResolution\": \"nodenext\"\n }\n}\n"
},
{
"path": "test/project-setups.test.ts",
"chars": 1789,
"preview": "import * as childProcess from \"node:child_process\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nim"
},
{
"path": "test/referrer-policy.test.ts",
"chars": 2138,
"preview": "import assert from \"node:assert/strict\";\nimport { describe, it } from \"node:test\";\nimport referrerPolicy from \"../middle"
},
{
"path": "test/source-files.test.ts",
"chars": 1805,
"preview": "import * as childProcess from \"node:child_process\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:"
},
{
"path": "test/strict-transport-security.test.ts",
"chars": 3976,
"preview": "import assert from \"node:assert/strict\";\nimport { describe, it } from \"node:test\";\nimport strictTransportSecurity from \""
},
{
"path": "test/x-content-type-options.test.ts",
"chars": 368,
"preview": "import { describe, it } from \"node:test\";\nimport xContentTypeOptions from \"../middlewares/x-content-type-options\";\nimpor"
},
{
"path": "test/x-dns-prefetch-control.test.ts",
"chars": 880,
"preview": "import { describe, it } from \"node:test\";\nimport xDnsPrefetchControl from \"../middlewares/x-dns-prefetch-control\";\nimpor"
},
{
"path": "test/x-download-options.test.ts",
"chars": 344,
"preview": "import { describe, it } from \"node:test\";\nimport xDownloadOptions from \"../middlewares/x-download-options\";\nimport { che"
},
{
"path": "test/x-frame-options.test.ts",
"chars": 2188,
"preview": "import assert from \"node:assert/strict\";\nimport { describe, it } from \"node:test\";\nimport xFrameOptions from \"../middlew"
},
{
"path": "test/x-permitted-cross-domain-policies.test.ts",
"chars": 1723,
"preview": "import assert from \"node:assert/strict\";\nimport { describe, it } from \"node:test\";\nimport xPermittedCrossDomainPolicies "
},
{
"path": "test/x-powered-by.test.ts",
"chars": 628,
"preview": "import { describe, it } from \"node:test\";\nimport xPoweredBy from \"../middlewares/x-powered-by\";\nimport { check } from \"."
},
{
"path": "test/x-xss-protection.test.ts",
"chars": 322,
"preview": "import { describe, it } from \"node:test\";\nimport xXssProtection from \"../middlewares/x-xss-protection\";\nimport { check }"
},
{
"path": "tsconfig.json",
"chars": 443,
"preview": "{\n \"compilerOptions\": {\n \"esModuleInterop\": true,\n \"module\": \"esnext\",\n \"moduleResolution\": \"node\",\n \"noFal"
}
]
About this extraction
This page contains the full source code of the helmetjs/helmet GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 104 files (190.7 KB), approximately 52.6k tokens, and a symbol index with 100 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.