Skip to content

feat: add request-scoped CSP nonces#3

Merged
smiggleworth merged 4 commits into
mainfrom
fix/document-preauth-action-csrf
Jul 23, 2026
Merged

feat: add request-scoped CSP nonces#3
smiggleworth merged 4 commits into
mainfrom
fix/document-preauth-action-csrf

Conversation

@smiggleworth

Copy link
Copy Markdown
Contributor

Adds request-memoized CSP nonce providers, callback CSP policies, and shared page/app nonce propagation. Includes the prepared server security hardening, protected workflow pin, regression coverage, and 0.0.9 release bump. Requires @askrjs/askr 0.0.64+.\n\nThe package-native release gate passes against the published registry artifact.

Copilot AI review requested due to automatic review settings July 23, 2026 16:45
@smiggleworth
smiggleworth merged commit 885d829 into main Jul 23, 2026
3 checks passed
@smiggleworth
smiggleworth deleted the fix/document-preauth-action-csrf branch July 23, 2026 16:48
Copilot stopped reviewing on behalf of smiggleworth due to an error July 23, 2026 16:56

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR tightens security defaults and adds support for CSP nonces and MCP session lifecycle controls (capacity + TTL), along with corresponding test updates.

Changes:

  • Add request-memoized CSP nonce support and allow dynamic CSP headers via securityHeaders().
  • Harden MCP HTTP origin/host validation and add default session store capacity/TTL with new tests.
  • Make rate limiting bucket selection explicit via a required key() function; adjust telemetry to avoid logging concrete URL paths.

Reviewed changes

Copilot reviewed 21 out of 22 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
tests/telemetry.test.ts Verifies route telemetry records template paths and avoids embedding concrete IDs.
tests/protection.test.ts Updates rate limit tests to provide explicit bucket keys.
tests/mcp.test.ts Adds coverage ensuring auth runs before completion handlers for resource templates.
tests/mcp-http.test.ts Expands HTTP MCP tests for origin checks, session creation timing, capacity, and TTL expiry.
tests/csp-nonce.test.ts Adds tests for request-memoized CSP nonces and dynamic/static CSP policies.
src/middleware/security-headers.ts Allows CSP policy to be a function of request context (enables nonce injection).
src/middleware/rate-limit.ts Makes key() mandatory and removes implicit proxy-header-based keying.
src/mcp/http.ts Requires allowedOrigins/allowedHosts, enforces Origin presence, adds memory session TTL/capacity and delayed session creation.
src/mcp/dispatch.ts Prevents completion of resource templates if not visible/authorized.
src/index.ts Exports CSP nonce utilities from the public package entrypoint.
src/csp-nonce.ts Implements request-memoized nonce generator (base64url).
src/auth.ts Strengthens cookie defaults (httpOnly/sameSite/path; secure defaults to true).
src/askr/page-handler.ts Plumbs cspNonce into page rendering and action invalid rerenders.
src/askr/app.ts Exposes cspNonce option on app creation and passes into page handler.
src/askr/actions.ts Removes action telemetry field that used concrete request pathname.
src/application.ts Adjusts telemetry route match fields to use matched route template instead of concrete pathname.
package.json Bumps package version and updates @askrjs/askr peer/dev ranges.
README.md Documents how to configure strict CSP nonces end-to-end.
.github/workflows/publish.yml Pins reusable publish workflow to a specific commit and changes secrets handling.
.github/workflows/ci.yml Pins GitHub Actions to specific commits.
.github/CODEOWNERS Adds repository-wide code owner.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/csp-nonce.ts
Comment on lines +10 to +14
const bytes = crypto.getRandomValues(new Uint8Array(24));
const generated = btoa(String.fromCharCode(...bytes))
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");
Comment thread src/application.ts
Comment on lines +48 to +58
const found = matcher.match(context.url.pathname, request.method);
if (options.telemetry) {
options.telemetry.routeMatch(
{
requestId,
traceId,
route: found.match?.route.path ?? "<unmatched>",
},
() => found,
);
}
Comment on lines +20 to +24
/**
* Returns an application-trusted bucket identity. Proxy headers are
* intentionally never interpreted by this middleware.
*/
readonly key: (context: Parameters<Middleware>[0]) => string;
options.key?.(context) ??
context.headers.get("x-forwarded-for")?.split(",", 1)[0]?.trim() ??
"anonymous";
const key = options.key(context);
Comment thread src/mcp/http.ts
Comment on lines +9 to +10
allowedOrigins: readonly string[];
allowedHosts: readonly string[];
Comment thread src/mcp/http.ts
Comment on lines +34 to 38
if (!origin || !options.allowedOrigins.includes(origin))
return context.forbidden("Origin is not allowed.");
const host = context.headers.get("host");
if (options.allowedHosts && (!host || !options.allowedHosts.includes(host)))
if (!host || !options.allowedHosts.includes(host))
return context.forbidden("Host is not allowed.");
Comment thread src/auth.ts
Comment on lines +160 to +164
httpOnly: true,
sameSite: "lax" as const,
path: "/",
...configuredCookie,
secure: configuredCookie.secure ?? context.url.protocol === "https:",
secure: configuredCookie.secure ?? true,
Comment thread src/auth.ts
Comment on lines +229 to +233
httpOnly: true,
sameSite: "lax" as const,
path: "/",
...configuredCookie,
secure: configuredCookie.secure ?? context.url.protocol === "https:",
secure: configuredCookie.secure ?? true,
Comment on lines +14 to 18
uses: askrjs/actions/.github/workflows/publish-package.yml@614b9e344983ad2100563c5f36f94d774d3ba6bd
permissions:
contents: write
id-token: write
packages: read
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants