Skip to content

feat(symfony): emit a csp nonce on the swagger ui and graphiql scripts#8310

Open
soyuka wants to merge 1 commit into
api-platform:mainfrom
soyuka:fix/swagger-csp-nonce-8142-impl
Open

feat(symfony): emit a csp nonce on the swagger ui and graphiql scripts#8310
soyuka wants to merge 1 commit into
api-platform:mainfrom
soyuka:fix/swagger-csp-nonce-8142-impl

Conversation

@soyuka

@soyuka soyuka commented Jun 16, 2026

Copy link
Copy Markdown
Member

Summary

Under a Content Security Policy such as script-src 'self' 'strict-dynamic', the bundled SwaggerUI and GraphiQL <script> tags were blocked because they carried no nonce. They now receive one, reusing existing mechanisms with no new config key:

  • a _csp_nonce request attribute (set by a proxy/middleware) takes precedence;
  • otherwise the nelmio csp_nonce('script') Twig function is reused when available — so the emitted nonce matches the one NelmioSecurityBundle adds to the CSP response header;
  • absent both, output is unchanged (no nonce attribute) so plain installs are unaffected.

The nonce is resolved in PHP (SwaggerUiProcessor / GraphiQlAction), not in Twig. This keeps any csp_nonce() call out of the templates: a literal csp_nonce() in a template would throw a Twig SyntaxError at parse time when the function is not registered, and a runtime {% if %} guard cannot prevent that. Resolving in PHP avoids the problem entirely — the template just emits the attribute when a nonce is present.

Scope

  • SwaggerUI (SwaggerUi/index.html.twig via SwaggerUiProcessor): inline data block, swagger/redoc/scalar bundles, init scripts.
  • GraphiQL (Graphiql/index.html.twig via GraphiQlAction): importmap, inline data block, init-graphiql.js module.

Out of scope: style-src nonces and the Scalar cdn.jsdelivr.net host (covered by strict-dynamic once a nonced script bootstraps). This PR addresses script-src only, per the issue.

Reproduction

Visiting /api or /graphql/graphiql with a strict CSP blocked the scripts (no nonce emitted).

Test plan

  • New SwaggerUiCspNonceTest and GraphiqlCspNonceTest (4 cases each): request-attribute nonce, csp_nonce() nonce, request-attr precedence over the function, and no-mechanism → no nonce attribute.
  • GraphiQlActionTest unit updated (stubs getFunction('csp_nonce')).
  • DocumentationActionTest regression green (9/9).
  • PHPStan (max) + php-cs-fixer clean on changed files.

Fixes #8142

@soyuka soyuka added OpenAPI Symfony Symfony bridge: routing/DI/eventlistener labels Jun 16, 2026
@soyuka soyuka force-pushed the fix/swagger-csp-nonce-8142-impl branch from c2b555d to 8ef0a96 Compare June 16, 2026 14:23
@soyuka soyuka changed the title fix(symfony): emit a csp nonce on the swagger ui scripts fix(symfony): emit a csp nonce on the swagger ui and graphiql scripts Jun 16, 2026
@soyuka soyuka force-pushed the fix/swagger-csp-nonce-8142-impl branch from 8ef0a96 to 355ce8a Compare June 16, 2026 14:29
@soyuka soyuka changed the base branch from 4.3 to main June 16, 2026 14:29
@soyuka soyuka changed the title fix(symfony): emit a csp nonce on the swagger ui and graphiql scripts feat(symfony): emit a csp nonce on the swagger ui and graphiql scripts Jun 16, 2026
Under a CSP like "script-src 'self' 'strict-dynamic'" the bundled SwaggerUI
and GraphiQL scripts were blocked because they carried no nonce. Emit one,
reusing existing mechanisms with no new config key: a `_csp_nonce` request
attribute takes precedence, otherwise the nelmio `csp_nonce('script')` Twig
function is reused (so the emitted nonce matches the one nelmio adds to the
CSP response header); absent both, output is unchanged.

The nonce is resolved in PHP, so no `csp_nonce()` call appears in the
templates and plain installs without nelmio are unaffected.

Fixes api-platform#8142
@soyuka soyuka force-pushed the fix/swagger-csp-nonce-8142-impl branch from 355ce8a to a9f111c Compare June 16, 2026 14:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

OpenAPI Symfony Symfony bridge: routing/DI/eventlistener

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Swagger UI scripts blocked by CSP when using 'strict-dynamic'

1 participant