feat(skills): full footgun hardening across all domains — skill guidance + scenarios (AX-106)#84
Conversation
📝 WalkthroughWalkthroughThis PR adds numerous new Axis test scenario files across many Netlify product areas (agent runner, AI gateway, blobs, caching, config, database, deploy, edge functions, forms, frameworks, functions, identity, image CDN, MCP servers), each defining a ChangesAxis Scenarios and Skills Documentation
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Codex review: I found two issues that should be addressed before merge.
Generated Codex/Cursor mirrors are in sync. I did not run AXIS tests per request. |
|
Codex review update: I re-audited the new PR head ( One blocking validation issue remains:
Even though the validator prints "16 skills validated: all passed", the command exits with status 1 under |
…skill-guidance-scenarios-for-confirmed-netlify-footguns # Conflicts: # codex/skills/netlify-caching/SKILL.md # codex/skills/netlify-forms/SKILL.md # codex/skills/netlify-functions/SKILL.md # cursor/rules/netlify-caching.mdc # cursor/rules/netlify-forms.mdc # cursor/rules/netlify-functions.mdc # skills/netlify-caching/SKILL.md # skills/netlify-forms/SKILL.md # skills/netlify-functions/SKILL.md
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
skills/netlify-blobs/SKILL.md (1)
114-164: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider moving detailed sections into
references/to avoid a future token-limit split.This diff adds several fairly detailed sections directly into
SKILL.md(Consistency/concurrency, CLI inspection, build-time uploads). The same PR had to splitnetlify-databaseandnetlify-identitySKILL.md files intoreferences/after they exceeded theskill-validator --stricttoken threshold. Proactively moving some of this detail (e.g., the CLI and build-time-upload sections, which are more specialized/less core) into areferences/file would keep this skill from hitting the same limit as the project grows.As per coding guidelines,
skills/**: "Usereferences/subdirectories for detailed content within skills."🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@skills/netlify-blobs/SKILL.md` around lines 114 - 164, The new detailed content in SKILL.md should be split to keep the skill file from growing toward the strict token limit. Move the less core sections such as the CLI blob inspection and build-time upload guidance into a references file under the skill’s references/ subdirectory, and leave only a short pointer in SKILL.md; keep the core consistency/concurrency overview there if needed. Use the existing section headings and related symbols like getStore, getDeployStore, and netlify blobs:* as anchors when relocating the content.Source: Coding guidelines
skills/netlify-mcp-servers/SKILL.md (1)
96-101: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winInsecure default for
Access-Control-Allow-Origin.The example defaults to
"*"whenMCP_ALLOWED_ORIGINis unset. This means any origin can make bearer-authenticated cross-origin calls to the endpoint out of the box if a developer copies this snippet without configuring the env var — silently widening exposure for a token-protected endpoint. Since this is a copy-paste reference example in a skill doc, consider defaulting to a required/explicit origin (or failing closed) rather than a permissive wildcard fallback.🔒 Suggested tightening
const CORS = { - "Access-Control-Allow-Origin": Netlify.env.get("MCP_ALLOWED_ORIGIN") ?? "*", + "Access-Control-Allow-Origin": Netlify.env.get("MCP_ALLOWED_ORIGIN") ?? "", "Access-Control-Allow-Methods": "POST, OPTIONS", "Access-Control-Allow-Headers": "Authorization, Content-Type, Mcp-Session-Id", };🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@skills/netlify-mcp-servers/SKILL.md` around lines 96 - 101, The CORS example in the Netlify MCP server skill uses a permissive wildcard fallback for Access-Control-Allow-Origin, which should be tightened. Update the CORS object so the origin is explicitly required from MCP_ALLOWED_ORIGIN or the example fails closed instead of defaulting to "*", and keep the guidance aligned with the surrounding MCP session/auth example so copy-pasters don’t accidentally expose a bearer-protected endpoint.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@skills/netlify-config/SKILL.md`:
- Line 10: The guidance currently overstates that netlify.toml is the source of
truth for all settings, but the comment clarifies this should be limited to
build-time configuration. Update the wording in SKILL.md to distinguish build
command, publish directory, redirects, and headers from environment variables,
and make clear that netlify.toml only covers build-scoped env vars while runtime
env vars must still be managed in the Netlify UI or via netlify env:set.
---
Nitpick comments:
In `@skills/netlify-blobs/SKILL.md`:
- Around line 114-164: The new detailed content in SKILL.md should be split to
keep the skill file from growing toward the strict token limit. Move the less
core sections such as the CLI blob inspection and build-time upload guidance
into a references file under the skill’s references/ subdirectory, and leave
only a short pointer in SKILL.md; keep the core consistency/concurrency overview
there if needed. Use the existing section headings and related symbols like
getStore, getDeployStore, and netlify blobs:* as anchors when relocating the
content.
In `@skills/netlify-mcp-servers/SKILL.md`:
- Around line 96-101: The CORS example in the Netlify MCP server skill uses a
permissive wildcard fallback for Access-Control-Allow-Origin, which should be
tightened. Update the CORS object so the origin is explicitly required from
MCP_ALLOWED_ORIGIN or the example fails closed instead of defaulting to "*", and
keep the guidance aligned with the surrounding MCP session/auth example so
copy-pasters don’t accidentally expose a bearer-protected endpoint.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 7e87c5f3-9b13-4044-86bd-edb13bb0cc4d
⛔ Files ignored due to path filters (44)
codex/skills/netlify-agent-runner/SKILL.mdis excluded by!codex/**codex/skills/netlify-ai-gateway/SKILL.mdis excluded by!codex/**codex/skills/netlify-blobs/SKILL.mdis excluded by!codex/**codex/skills/netlify-caching/SKILL.mdis excluded by!codex/**codex/skills/netlify-cli-and-deploy/SKILL.mdis excluded by!codex/**codex/skills/netlify-config/SKILL.mdis excluded by!codex/**codex/skills/netlify-database/SKILL.mdis excluded by!codex/**codex/skills/netlify-database/references/operational-footguns.mdis excluded by!codex/**codex/skills/netlify-deploy/SKILL.mdis excluded by!codex/**codex/skills/netlify-edge-functions/SKILL.mdis excluded by!codex/**codex/skills/netlify-forms/SKILL.mdis excluded by!codex/**codex/skills/netlify-frameworks/SKILL.mdis excluded by!codex/**codex/skills/netlify-frameworks/references/astro.mdis excluded by!codex/**codex/skills/netlify-frameworks/references/nextjs.mdis excluded by!codex/**codex/skills/netlify-frameworks/references/nuxt.mdis excluded by!codex/**codex/skills/netlify-frameworks/references/sveltekit.mdis excluded by!codex/**codex/skills/netlify-functions/SKILL.mdis excluded by!codex/**codex/skills/netlify-identity/SKILL.mdis excluded by!codex/**codex/skills/netlify-identity/references/authorization-and-sessions.mdis excluded by!codex/**codex/skills/netlify-image-cdn/SKILL.mdis excluded by!codex/**codex/skills/netlify-mcp-servers/SKILL.mdis excluded by!codex/**codex/skills/netlify-mcp-servers/references/file-uploads.mdis excluded by!codex/**cursor/rules/netlify-agent-runner.mdcis excluded by!cursor/**cursor/rules/netlify-ai-gateway.mdcis excluded by!cursor/**cursor/rules/netlify-blobs.mdcis excluded by!cursor/**cursor/rules/netlify-caching.mdcis excluded by!cursor/**cursor/rules/netlify-cli-and-deploy.mdcis excluded by!cursor/**cursor/rules/netlify-config.mdcis excluded by!cursor/**cursor/rules/netlify-database-operational-footguns.mdcis excluded by!cursor/**cursor/rules/netlify-database.mdcis excluded by!cursor/**cursor/rules/netlify-deploy.mdcis excluded by!cursor/**cursor/rules/netlify-edge-functions.mdcis excluded by!cursor/**cursor/rules/netlify-forms.mdcis excluded by!cursor/**cursor/rules/netlify-frameworks-astro.mdcis excluded by!cursor/**cursor/rules/netlify-frameworks-nextjs.mdcis excluded by!cursor/**cursor/rules/netlify-frameworks-nuxt.mdcis excluded by!cursor/**cursor/rules/netlify-frameworks-sveltekit.mdcis excluded by!cursor/**cursor/rules/netlify-frameworks.mdcis excluded by!cursor/**cursor/rules/netlify-functions.mdcis excluded by!cursor/**cursor/rules/netlify-identity-authorization-and-sessions.mdcis excluded by!cursor/**cursor/rules/netlify-identity.mdcis excluded by!cursor/**cursor/rules/netlify-image-cdn.mdcis excluded by!cursor/**cursor/rules/netlify-mcp-servers-file-uploads.mdcis excluded by!cursor/**cursor/rules/netlify-mcp-servers.mdcis excluded by!cursor/**
📒 Files selected for processing (90)
axis-scenarios/agent-runner/list-scope.tsaxis-scenarios/agent-runner/output-new-branch.tsaxis-scenarios/agent-runner/plan-credits.tsaxis-scenarios/ai-gateway/browser-proxy-through-function.tsaxis-scenarios/ai-gateway/build-time-gateway-access.tsaxis-scenarios/ai-gateway/local-dev-requires-linked-project.tsaxis-scenarios/ai-gateway/long-generation-timeout.tsaxis-scenarios/blobs/build-time-uploads.tsaxis-scenarios/blobs/cli-inspect.tsaxis-scenarios/blobs/concurrency-last-write-wins.tsaxis-scenarios/blobs/list-pagination.tsaxis-scenarios/blobs/metadata-size-cap.tsaxis-scenarios/blobs/per-operation-consistency.tsaxis-scenarios/blobs/site-scoped-shared-across-contexts.tsaxis-scenarios/caching/cache-status-interpret.tsaxis-scenarios/caching/get-only-caching.tsaxis-scenarios/caching/local-dev-no-cache.tsaxis-scenarios/caching/purge-cache-external-token.tsaxis-scenarios/caching/query-string-cache-key.tsaxis-scenarios/config/context-scoped-redirects.tsaxis-scenarios/config/dev-custom-framework.tsaxis-scenarios/config/redirects-file-vs-toml-order.tsaxis-scenarios/config/toml-env-build-scope.tsaxis-scenarios/config/toml-overrides-ui.tsaxis-scenarios/database/db-connection-reuse-module-scope.tsaxis-scenarios/database/db-legacy-unclaimed-deletion.tsaxis-scenarios/database/db-preview-url-exposes-production-data.tsaxis-scenarios/database/db-scale-to-zero-cold-start.tsaxis-scenarios/deploy/branch-deploys-off-by-default.tsaxis-scenarios/deploy/ci-site-id.tsaxis-scenarios/deploy/lock-deploy-manual-prod.tsaxis-scenarios/deploy/monorepo-config-discovery.tsaxis-scenarios/deploy/preview-url-public-by-link.tsaxis-scenarios/deploy/secrets-scan-build-failure.tsaxis-scenarios/deploy/toml-overrides-ui.tsaxis-scenarios/edge-functions/chain-order.tsaxis-scenarios/edge-functions/context-cookies.tsaxis-scenarios/edge-functions/path-static-asset-interception.tsaxis-scenarios/edge-functions/redirect-order.tsaxis-scenarios/edge-functions/undeclared-function.tsaxis-scenarios/forms/custom-recaptcha-keys.tsaxis-scenarios/forms/json-body-not-supported.tsaxis-scenarios/forms/redeploy-after-enabling-detection.tsaxis-scenarios/forms/spam-missing-submissions.tsaxis-scenarios/forms/submissions-api-pagination.tsaxis-scenarios/frameworks/astro-form-detection.tsaxis-scenarios/frameworks/env-var-build-time-redeploy.tsaxis-scenarios/frameworks/nextjs-runtime-version-floor.tsaxis-scenarios/frameworks/nuxt-adapter.tsaxis-scenarios/frameworks/runtime-file-reads.tsaxis-scenarios/frameworks/spa-catchall-shadows-ssr.tsaxis-scenarios/frameworks/sveltekit-adapter.tsaxis-scenarios/functions/functions-env-var-size-limit.tsaxis-scenarios/functions/functions-geo-local-dev.tsaxis-scenarios/functions/functions-included-files.tsaxis-scenarios/functions/functions-scheduled-local-testing.tsaxis-scenarios/functions/functions-scheduled-no-url.tsaxis-scenarios/identity/admin-role-assignment-server-side.tsaxis-scenarios/identity/role-change-requires-reauth.tsaxis-scenarios/identity/role-gate-server-side-authz.tsaxis-scenarios/image-cdn/blurhash-placeholder.tsaxis-scenarios/image-cdn/local-dev.tsaxis-scenarios/image-cdn/remote-not-allowlisted.tsaxis-scenarios/mcp-servers/browser-client-cors.tsaxis-scenarios/mcp-servers/hosted-vs-custom-mcp.tsaxis-scenarios/mcp-servers/rate-limiting.tsaxis-scenarios/mcp-servers/secrets-scanning-token.tsaxis-scenarios/mcp-servers/stateless-replay-tracking.tsskills/netlify-agent-runner/SKILL.mdskills/netlify-ai-gateway/SKILL.mdskills/netlify-blobs/SKILL.mdskills/netlify-caching/SKILL.mdskills/netlify-cli-and-deploy/SKILL.mdskills/netlify-config/SKILL.mdskills/netlify-database/SKILL.mdskills/netlify-database/references/operational-footguns.mdskills/netlify-deploy/SKILL.mdskills/netlify-edge-functions/SKILL.mdskills/netlify-forms/SKILL.mdskills/netlify-frameworks/SKILL.mdskills/netlify-frameworks/references/astro.mdskills/netlify-frameworks/references/nextjs.mdskills/netlify-frameworks/references/nuxt.mdskills/netlify-frameworks/references/sveltekit.mdskills/netlify-functions/SKILL.mdskills/netlify-identity/SKILL.mdskills/netlify-identity/references/authorization-and-sessions.mdskills/netlify-image-cdn/SKILL.mdskills/netlify-mcp-servers/SKILL.mdskills/netlify-mcp-servers/references/file-uploads.md
|
|
||
| Place `netlify.toml` at the repository root (or at the base directory for monorepos). | ||
|
|
||
| **`netlify.toml` takes precedence over the Netlify UI.** When the same property (build command, publish directory, an environment variable, a redirect, a header) is configured in both places, the value in `netlify.toml` wins and silently overrides the corresponding Netlify UI setting — the dashboard field still shows its old value but is inert. Once a `netlify.toml` is present, treat it as the source of truth and change settings there, not in the UI. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file='skills/netlify-config/SKILL.md'
printf '\n== File info ==\n'
wc -l "$file"
printf '\n== Outline ==\n'
ast-grep outline "$file" --view expanded || true
printf '\n== Relevant ranges ==\n'
sed -n '1,40p' "$file" | cat -n
printf '\n---\n'
sed -n '130,190p' "$file" | cat -nRepository: netlify/context-and-tools
Length of output: 4740
Scope this to build-time settings. netlify.toml does override the UI for build settings, redirects, and headers, but its environment variables are build-scoped only; runtime env vars still need the UI or netlify env:set.
🧰 Tools
🪛 SkillSpector (2.3.7)
[warning] 57: [E1] External Transmission: Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
Remediation: Verify the destination URL is trusted and necessary. Remove or replace with documented APIs. Ensure no secrets, tokens, or PII are transmitted.
(Data Exfiltration (E1))
[warning] 107: [TM3] Unsafe Defaults: Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.
Remediation: Override unsafe defaults with secure settings (verify=True, auth required, restrictive permissions). Review and harden all tool configurations.
(Tool Misuse (TM3))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@skills/netlify-config/SKILL.md` at line 10, The guidance currently overstates
that netlify.toml is the source of truth for all settings, but the comment
clarifies this should be limited to build-time configuration. Update the wording
in SKILL.md to distinguish build command, publish directory, redirects, and
headers from environment variables, and make clear that netlify.toml only covers
build-scoped env vars while runtime env vars must still be managed in the
Netlify UI or via netlify env:set.
Summary
Full footgun-hardening pass (AX-106) — adds skill guidance and a covering scenario for every confirmed §C footgun the audit found, across all 14 domains. (Supersedes the initial six-footgun tranche.)
What changed
SECRETS_SCAN_*), per-invocation DB connection exhaustion (reuse module-scopegetDatabase()), Blobs metadata cap + cross-deploy-context sharing, AI-Gateway credit metering + runtime-only credentials, edgepath: "/*"asset interception + inert-without-cache: "manual", forms JSON-body-not-supported + submissions pagination, confignetlify.toml-overrides-UI + build-scoped env vars, framework runtime-fs reads / SPA-catchall-shadows-SSR + Nuxt & SvelteKit setup references, functions env-var 4 KB cap +included_files, identity admin-runtime/role-session gotchas, MCP CORS/rate-limit/function-timeout, and more.netlify-database/netlify-identity: the added footgun detail is factored intoreferences/operational-footguns.mdandreferences/authorization-and-sessions.md(withSKILL.mdpointers) so both stay under theskill-validatortoken limit —skill-validator check --strict skills/passes.Skips the 8 refuted + 8 unverifiable footguns per §C (no stale pricing/limits).
Closes AX-106.
Summary by CodeRabbit