docmirror/dev-sidecar · warning

getNonce: CSP 存在但未匹配到 nonce, CSP:

Error message

getNonce: CSP 存在但未匹配到 nonce, CSP:

What it means

When injecting scripts into an HTML response, the library extracts the CSP nonce from the response's `content-security-policy` (or report-only) header so injected <script> tags are allowed. If a CSP header exists but its text contains no `nonce-xxx` token matching the regex, it logs this warning (truncated to 500 chars) and returns an empty string — the injected script then has no nonce attribute.

Source

Thrown at packages/mitmproxy/src/lib/interceptor/impl/res/script.js:27

function getScript (key, script, nonce) {
  const scriptUrl = SCRIPT_URL_PRE + key
  return `<script crossorigin="anonymous" defer="defer" type="application/javascript" src="${scriptUrl}"${nonce}></script>`
}
function getScriptByUrlOrPath (scriptUrlOrPath, nonce) {
  return `<script crossorigin="anonymous" defer="defer" type="application/javascript" src="${scriptUrlOrPath}"${nonce}></script>`
}

// 从 CSP 头中提取 nonce 值,用于注入脚本以通过 'strict-dynamic' 检查
function getNonceAttr (proxyRes) {
  // CSP 可能在 content-security-policy 或 content-security-policy-report-only 中
  const csp = proxyRes.headers['content-security-policy']
    || proxyRes.headers['content-security-policy-report-only']
  if (!csp) return ''
  // 支持单引号和双引号包裹的 nonce 值
  const match = csp.match(/['"]nonce-([^'"]+)['"]/)
  if (!match) {
    log.warn('getNonce: CSP 存在但未匹配到 nonce, CSP:', csp.substring(0, 500))
    return ''
  }
  return ` nonce="${match[1]}"`
}

module.exports = {
  name: 'script',
  priority: 211,
  responseIntercept (context, interceptOpt, req, res, proxyReq, proxyRes, ssl, next) {
    const { rOptions, log, setting } = context

    // github特殊处理
    if (rOptions.hostname === 'github.com' && rOptions.headers['turbo-frame'] === 'repo-content-turbo-frame') {
      return
    }

    // 如果没有响应头 'content-type',或其值不是 'text/html',则不处理
    if (!proxyRes.headers['content-type'] || !proxyRes.headers['content-type'].includes('text/html')) {

View on GitHub (pinned to 7710cd56cc)

Solutions

  1. Disable script injection for that domain in the interceptor config if nonce injection cannot succeed.
  2. Verify the CSP actually contains a script-src nonce (check response headers in DevTools); if only hashes are used, nonces cannot be extracted by design.
  3. Configure the site/server to include 'nonce-<value>' in its script-src so the regex matches.
  4. Ignore the warning for report-only CSPs — they enforce nothing, but injection may still be blocked elsewhere; check console for CSP violations.

Example fix

// server before
Content-Security-Policy: script-src 'self' 'unsafe-inline'
// after
Content-Security-Policy: script-src 'self' 'nonce-r4nd0mValue'
Defensive patterns

Strategy: fallback

Validate before calling

const csp = res.headers['content-security-policy'] || ''
const hasNonce = /['"]nonce-[^'"]+['"]/.test(csp)
if (csp && !hasNonce) disableScriptInjectionForThisDomain()

Type guard

const cspHasNonce = (csp) => typeof csp === 'string' && /['"]nonce-([^'"]+)['"]/.test(csp)

Prevention

When it happens

Trigger: A proxied site sends a CSP header without any script-src nonce directive (e.g. only 'unsafe-inline', hashes, or strict-dynamic without nonce), while script injection is enabled for that domain.

Common situations: Sites using CSP hash-based policies; report-only CSPs without nonces; CDNs or servers stripping nonces; dynamically generated CSPs with unusual quoting.


AI-assisted analysis of docmirror/dev-sidecar@7710cd56cc (2026-08-31). Data as JSON: /api/errors/e31752ff9cc1aad1. Report an issue: GitHub.