cfsa-antigravity 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.mjs +324 -0
- package/package.json +34 -0
- package/template/.agent/instructions/commands.md +48 -0
- package/template/.agent/instructions/patterns.md +61 -0
- package/template/.agent/instructions/structure.md +29 -0
- package/template/.agent/instructions/tech-stack.md +43 -0
- package/template/.agent/instructions/workflow.md +41 -0
- package/template/.agent/kit-sync.md +15 -0
- package/template/.agent/rules/boundary-not-placeholder.md +146 -0
- package/template/.agent/rules/completion-checklist.md +48 -0
- package/template/.agent/rules/decision-classification.md +103 -0
- package/template/.agent/rules/extensibility.md +47 -0
- package/template/.agent/rules/question-vs-command.md +81 -0
- package/template/.agent/rules/security-first.md +43 -0
- package/template/.agent/rules/specificity-standards.md +54 -0
- package/template/.agent/rules/tdd-contract-first.md +57 -0
- package/template/.agent/rules/vertical-slices.md +42 -0
- package/template/.agent/skill-library/MANIFEST.md +480 -0
- package/template/.agent/skill-library/README.md +38 -0
- package/template/.agent/skill-library/meta/brand-guidelines/SKILL.md +73 -0
- package/template/.agent/skill-library/meta/claude-code/README.md +9 -0
- package/template/.agent/skill-library/meta/claude-code/agent-development/SKILL.md +415 -0
- package/template/.agent/skill-library/meta/claude-code/hook-development/SKILL.md +712 -0
- package/template/.agent/skill-library/meta/claude-code/plugin-structure/SKILL.md +476 -0
- package/template/.agent/skill-library/meta/git-advanced/SKILL.md +972 -0
- package/template/.agent/skill-library/meta/mcp-builder/SKILL.md +236 -0
- package/template/.agent/skill-library/meta/product-marketing-context/SKILL.md +241 -0
- package/template/.agent/skill-library/meta/regex-patterns/SKILL.md +751 -0
- package/template/.agent/skill-library/meta/tmux-processes/SKILL.md +210 -0
- package/template/.agent/skill-library/meta/using-tmux-for-interactive-commands/SKILL.md +178 -0
- package/template/.agent/skill-library/stack/3d/threejs-pro/SKILL.md +300 -0
- package/template/.agent/skill-library/stack/ai/ai-sdk/SKILL.md +77 -0
- package/template/.agent/skill-library/stack/ai/langchain/SKILL.md +530 -0
- package/template/.agent/skill-library/stack/ai/ollama/SKILL.md +321 -0
- package/template/.agent/skill-library/stack/ai/openai-sdk/SKILL.md +549 -0
- package/template/.agent/skill-library/stack/analytics/google-analytics/SKILL.md +153 -0
- package/template/.agent/skill-library/stack/api/graphql/SKILL.md +1061 -0
- package/template/.agent/skill-library/stack/api/trpc/SKILL.md +576 -0
- package/template/.agent/skill-library/stack/auth/authjs/SKILL.md +569 -0
- package/template/.agent/skill-library/stack/auth/clerk/SKILL.md +590 -0
- package/template/.agent/skill-library/stack/auth/firebase-auth/SKILL.md +734 -0
- package/template/.agent/skill-library/stack/cms/payload-cms/SKILL.md +573 -0
- package/template/.agent/skill-library/stack/cms/shopify/SKILL.md +1193 -0
- package/template/.agent/skill-library/stack/cms/wordpress/SKILL.md +1104 -0
- package/template/.agent/skill-library/stack/css/sass-scss/SKILL.md +1121 -0
- package/template/.agent/skill-library/stack/css/tailwind-css-patterns/SKILL.md +863 -0
- package/template/.agent/skill-library/stack/css/tailwind-design-system/SKILL.md +490 -0
- package/template/.agent/skill-library/stack/css/vanilla-css/SKILL.md +1078 -0
- package/template/.agent/skill-library/stack/databases/clickhouse/SKILL.md +311 -0
- package/template/.agent/skill-library/stack/databases/influxdb/SKILL.md +280 -0
- package/template/.agent/skill-library/stack/databases/lancedb/SKILL.md +415 -0
- package/template/.agent/skill-library/stack/databases/mongodb/SKILL.md +1169 -0
- package/template/.agent/skill-library/stack/databases/neo4j/SKILL.md +839 -0
- package/template/.agent/skill-library/stack/databases/pgvector/SKILL.md +241 -0
- package/template/.agent/skill-library/stack/databases/pinecone/SKILL.md +212 -0
- package/template/.agent/skill-library/stack/databases/postgresql/SKILL.md +658 -0
- package/template/.agent/skill-library/stack/databases/qdrant/SKILL.md +312 -0
- package/template/.agent/skill-library/stack/databases/redis/SKILL.md +1079 -0
- package/template/.agent/skill-library/stack/databases/spacetimedb/SKILL.md +532 -0
- package/template/.agent/skill-library/stack/databases/sqlite/SKILL.md +1132 -0
- package/template/.agent/skill-library/stack/databases/supabase/SKILL.md +640 -0
- package/template/.agent/skill-library/stack/databases/surrealdb-expert/SKILL.md +945 -0
- package/template/.agent/skill-library/stack/databases/timescaledb/SKILL.md +745 -0
- package/template/.agent/skill-library/stack/databases/weaviate/SKILL.md +218 -0
- package/template/.agent/skill-library/stack/devops/github-actions/SKILL.md +554 -0
- package/template/.agent/skill-library/stack/devops/kubernetes/SKILL.md +950 -0
- package/template/.agent/skill-library/stack/devops/nginx/SKILL.md +841 -0
- package/template/.agent/skill-library/stack/devops/terraform/SKILL.md +860 -0
- package/template/.agent/skill-library/stack/email/resend/SKILL.md +391 -0
- package/template/.agent/skill-library/stack/engines/godot/SKILL.md +488 -0
- package/template/.agent/skill-library/stack/extensions/chrome-extension/SKILL.md +375 -0
- package/template/.agent/skill-library/stack/extensions/vscode-extension/SKILL.md +453 -0
- package/template/.agent/skill-library/stack/frameworks/astro-framework/SKILL.md +162 -0
- package/template/.agent/skill-library/stack/frameworks/electron/SKILL.md +1286 -0
- package/template/.agent/skill-library/stack/frameworks/fastapi/SKILL.md +650 -0
- package/template/.agent/skill-library/stack/frameworks/hono/SKILL.md +90 -0
- package/template/.agent/skill-library/stack/frameworks/nestjs/SKILL.md +878 -0
- package/template/.agent/skill-library/stack/frameworks/nextjs/SKILL.md +635 -0
- package/template/.agent/skill-library/stack/frameworks/nuxt/SKILL.md +564 -0
- package/template/.agent/skill-library/stack/frameworks/sveltekit/SKILL.md +614 -0
- package/template/.agent/skill-library/stack/frameworks/tauri/SKILL.md +920 -0
- package/template/.agent/skill-library/stack/gamedev/godot/SKILL.md +1032 -0
- package/template/.agent/skill-library/stack/gamedev/unity/SKILL.md +1175 -0
- package/template/.agent/skill-library/stack/hosting/aws/SKILL.md +467 -0
- package/template/.agent/skill-library/stack/hosting/cloudflare/SKILL.md +201 -0
- package/template/.agent/skill-library/stack/hosting/docker-expert/SKILL.md +409 -0
- package/template/.agent/skill-library/stack/hosting/vercel/SKILL.md +484 -0
- package/template/.agent/skill-library/stack/languages/bash-scripting/SKILL.md +773 -0
- package/template/.agent/skill-library/stack/languages/c-cpp/SKILL.md +712 -0
- package/template/.agent/skill-library/stack/languages/gdscript/SKILL.md +789 -0
- package/template/.agent/skill-library/stack/languages/go/SKILL.md +664 -0
- package/template/.agent/skill-library/stack/languages/java/SKILL.md +778 -0
- package/template/.agent/skill-library/stack/languages/kotlin/SKILL.md +665 -0
- package/template/.agent/skill-library/stack/languages/python/SKILL.md +678 -0
- package/template/.agent/skill-library/stack/languages/rust/SKILL.md +673 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/SKILL.md +141 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/advanced-generics.md +90 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/branded-types.md +57 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/builder-pattern.md +71 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/common-pitfalls.md +135 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/conditional-types.md +27 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/decorators.md +98 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/discriminated-unions.md +62 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/mapped-types.md +53 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/performance-best-practices.md +104 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/template-literal-types.md +49 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/testing-types.md +112 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/type-guards.md +70 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/type-inference.md +101 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/utility-types.md +98 -0
- package/template/.agent/skill-library/stack/languages/vanilla-javascript/SKILL.md +803 -0
- package/template/.agent/skill-library/stack/messaging/kafka/SKILL.md +235 -0
- package/template/.agent/skill-library/stack/mobile/expo-react-native/SKILL.md +665 -0
- package/template/.agent/skill-library/stack/mobile/flutter/SKILL.md +316 -0
- package/template/.agent/skill-library/stack/mobile/react-native/SKILL.md +337 -0
- package/template/.agent/skill-library/stack/monitoring/posthog/SKILL.md +396 -0
- package/template/.agent/skill-library/stack/monitoring/sentry/SKILL.md +509 -0
- package/template/.agent/skill-library/stack/observability/datadog/SKILL.md +179 -0
- package/template/.agent/skill-library/stack/observability/distributed-tracing/SKILL.md +140 -0
- package/template/.agent/skill-library/stack/observability/logging-best-practices/SKILL.md +168 -0
- package/template/.agent/skill-library/stack/observability/opentelemetry/SKILL.md +164 -0
- package/template/.agent/skill-library/stack/observability/prometheus-grafana/SKILL.md +246 -0
- package/template/.agent/skill-library/stack/observability/python-observability/SKILL.md +158 -0
- package/template/.agent/skill-library/stack/orm/drizzle-orm/SKILL.md +613 -0
- package/template/.agent/skill-library/stack/orm/prisma/SKILL.md +744 -0
- package/template/.agent/skill-library/stack/payments/lemonsqueezy/SKILL.md +393 -0
- package/template/.agent/skill-library/stack/payments/stripe-integration/SKILL.md +457 -0
- package/template/.agent/skill-library/stack/queue/bullmq/SKILL.md +385 -0
- package/template/.agent/skill-library/stack/queue/inngest/SKILL.md +438 -0
- package/template/.agent/skill-library/stack/realtime/socketio/SKILL.md +595 -0
- package/template/.agent/skill-library/stack/search/elasticsearch/SKILL.md +248 -0
- package/template/.agent/skill-library/stack/search/meilisearch/SKILL.md +385 -0
- package/template/.agent/skill-library/stack/security/crypto-patterns/SKILL.md +437 -0
- package/template/.agent/skill-library/stack/security/csp-cors-headers/SKILL.md +588 -0
- package/template/.agent/skill-library/stack/security/dependency-auditing/SKILL.md +560 -0
- package/template/.agent/skill-library/stack/security/input-sanitization/SKILL.md +430 -0
- package/template/.agent/skill-library/stack/security/owasp-web-security/SKILL.md +421 -0
- package/template/.agent/skill-library/stack/state/tanstack-query/SKILL.md +637 -0
- package/template/.agent/skill-library/stack/state/zustand/SKILL.md +483 -0
- package/template/.agent/skill-library/stack/storage/aws-s3/SKILL.md +415 -0
- package/template/.agent/skill-library/stack/testing/playwright/SKILL.md +641 -0
- package/template/.agent/skill-library/stack/testing/storybook/SKILL.md +923 -0
- package/template/.agent/skill-library/stack/testing/testing-library/SKILL.md +872 -0
- package/template/.agent/skill-library/stack/testing/vitest/SKILL.md +714 -0
- package/template/.agent/skill-library/stack/ui/react-best-practices/SKILL.md +877 -0
- package/template/.agent/skill-library/stack/ui/react-composition-patterns/SKILL.md +1107 -0
- package/template/.agent/skill-library/stack/ui/react-flow/SKILL.md +425 -0
- package/template/.agent/skill-library/stack/ui/shadcn-ui/SKILL.md +703 -0
- package/template/.agent/skill-library/surface/api/api-caching/SKILL.md +458 -0
- package/template/.agent/skill-library/surface/api/api-documentation-openapi/SKILL.md +697 -0
- package/template/.agent/skill-library/surface/api/api-error-handling/SKILL.md +478 -0
- package/template/.agent/skill-library/surface/api/api-security-checklist/SKILL.md +147 -0
- package/template/.agent/skill-library/surface/api/api-versioning/SKILL.md +420 -0
- package/template/.agent/skill-library/surface/api/email-best-practices/SKILL.md +59 -0
- package/template/.agent/skill-library/surface/api/rate-limiting-abuse-protection/SKILL.md +147 -0
- package/template/.agent/skill-library/surface/api/rest-api-design/SKILL.md +478 -0
- package/template/.agent/skill-library/surface/api/webhook-design/SKILL.md +752 -0
- package/template/.agent/skill-library/surface/cli/cli-configuration-management/SKILL.md +445 -0
- package/template/.agent/skill-library/surface/cli/cli-error-diagnostics/SKILL.md +515 -0
- package/template/.agent/skill-library/surface/cli/cli-shell-integration/SKILL.md +479 -0
- package/template/.agent/skill-library/surface/cli/cli-ux-design/SKILL.md +477 -0
- package/template/.agent/skill-library/surface/desktop/desktop-app-distribution/SKILL.md +416 -0
- package/template/.agent/skill-library/surface/desktop/desktop-security-sandboxing/SKILL.md +407 -0
- package/template/.agent/skill-library/surface/desktop/desktop-ux-conventions/SKILL.md +361 -0
- package/template/.agent/skill-library/surface/desktop/native-os-integration/SKILL.md +563 -0
- package/template/.agent/skill-library/surface/extension/browser-extension-patterns/SKILL.md +482 -0
- package/template/.agent/skill-library/surface/extension/plugin-architecture-design/SKILL.md +632 -0
- package/template/.agent/skill-library/surface/extension/vscode-extension-development/SKILL.md +728 -0
- package/template/.agent/skill-library/surface/mobile/app-store-submission/SKILL.md +304 -0
- package/template/.agent/skill-library/surface/mobile/mobile-offline-sync/SKILL.md +443 -0
- package/template/.agent/skill-library/surface/mobile/mobile-responsive-patterns/SKILL.md +432 -0
- package/template/.agent/skill-library/surface/mobile/push-notifications/SKILL.md +495 -0
- package/template/.agent/skill-library/surface/web/accessibility-compliance/SKILL.md +827 -0
- package/template/.agent/skill-library/surface/web/ai-seo/SKILL.md +398 -0
- package/template/.agent/skill-library/surface/web/ai-seo/references/content-patterns.md +285 -0
- package/template/.agent/skill-library/surface/web/ai-seo/references/platform-ranking-factors.md +152 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/SKILL.md +309 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/event-library.md +260 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/ga4-implementation.md +300 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/gtm-implementation.md +390 -0
- package/template/.agent/skill-library/surface/web/authentication-ui-flows/SKILL.md +530 -0
- package/template/.agent/skill-library/surface/web/dark-mode-theming/SKILL.md +516 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/SKILL.md +105 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/charts.csv +26 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/colors.csv +97 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/landing.csv +31 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/styles.csv +59 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/typography.csv +58 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/ux-guidelines.csv +100 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/core.py +258 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/design_system.py +1067 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/search.py +106 -0
- package/template/.agent/skill-library/surface/web/form-handling-validation/SKILL.md +675 -0
- package/template/.agent/skill-library/surface/web/frontend-design/SKILL.md +1393 -0
- package/template/.agent/skill-library/surface/web/frontend-design/templates/cppn-hero.tsx +299 -0
- package/template/.agent/skill-library/surface/web/frontend-design/templates/wave-hero.tsx +875 -0
- package/template/.agent/skill-library/surface/web/frontend-verification/SKILL.md +111 -0
- package/template/.agent/skill-library/surface/web/frontend-verification/scripts/ux_audit.py +739 -0
- package/template/.agent/skill-library/surface/web/i18n-localization/SKILL.md +154 -0
- package/template/.agent/skill-library/surface/web/offline-first-pwa/SKILL.md +657 -0
- package/template/.agent/skill-library/surface/web/page-cro/SKILL.md +182 -0
- package/template/.agent/skill-library/surface/web/page-cro/references/experiments.md +248 -0
- package/template/.agent/skill-library/surface/web/programmatic-seo/SKILL.md +238 -0
- package/template/.agent/skill-library/surface/web/programmatic-seo/references/playbooks.md +308 -0
- package/template/.agent/skill-library/surface/web/schema-markup/SKILL.md +179 -0
- package/template/.agent/skill-library/surface/web/schema-markup/references/schema-examples.md +398 -0
- package/template/.agent/skill-library/surface/web/seo-audit/SKILL.md +394 -0
- package/template/.agent/skill-library/surface/web/seo-audit/references/ai-writing-detection.md +200 -0
- package/template/.agent/skill-library/surface/web/web-performance-optimization/SKILL.md +646 -0
- package/template/.agent/skill-library/surface/web/web-scraping/SKILL.md +58 -0
- package/template/.agent/skills/accessibility/SKILL.md +522 -0
- package/template/.agent/skills/accessibility/references/WCAG.md +162 -0
- package/template/.agent/skills/adversarial-review/SKILL.md +90 -0
- package/template/.agent/skills/antigravity-workflows/SKILL.md +81 -0
- package/template/.agent/skills/antigravity-workflows/resources/implementation-playbook.md +36 -0
- package/template/.agent/skills/api-design-principles/SKILL.md +37 -0
- package/template/.agent/skills/api-design-principles/assets/api-design-checklist.md +155 -0
- package/template/.agent/skills/api-design-principles/assets/rest-api-template.py +182 -0
- package/template/.agent/skills/api-design-principles/references/graphql-schema-design.md +583 -0
- package/template/.agent/skills/api-design-principles/references/rest-best-practices.md +408 -0
- package/template/.agent/skills/api-design-principles/resources/implementation-playbook.md +513 -0
- package/template/.agent/skills/api-versioning/SKILL.md +420 -0
- package/template/.agent/skills/architecture-mapping/SKILL.md +219 -0
- package/template/.agent/skills/bootstrap-agents/SKILL.md +259 -0
- package/template/.agent/skills/brainstorming/SKILL.md +236 -0
- package/template/.agent/skills/brand-guidelines/SKILL.md +44 -0
- package/template/.agent/skills/clean-code/SKILL.md +94 -0
- package/template/.agent/skills/code-review-pro/SKILL.md +152 -0
- package/template/.agent/skills/concise-planning/SKILL.md +68 -0
- package/template/.agent/skills/cross-layer-consistency/SKILL.md +117 -0
- package/template/.agent/skills/database-schema-design/SKILL.md +429 -0
- package/template/.agent/skills/deployment-procedures/SKILL.md +241 -0
- package/template/.agent/skills/design-anti-cliche/SKILL.md +159 -0
- package/template/.agent/skills/design-direction/SKILL.md +45 -0
- package/template/.agent/skills/error-handling-patterns/SKILL.md +721 -0
- package/template/.agent/skills/find-skills/SKILL.md +145 -0
- package/template/.agent/skills/git-advanced/SKILL.md +972 -0
- package/template/.agent/skills/git-workflow/SKILL.md +420 -0
- package/template/.agent/skills/idea-extraction/SKILL.md +271 -0
- package/template/.agent/skills/logging-best-practices/SKILL.md +851 -0
- package/template/.agent/skills/migration-management/SKILL.md +384 -0
- package/template/.agent/skills/minimalist-surgical-development/SKILL.md +69 -0
- package/template/.agent/skills/parallel-agents/SKILL.md +165 -0
- package/template/.agent/skills/parallel-debugging/SKILL.md +135 -0
- package/template/.agent/skills/parallel-feature-development/SKILL.md +166 -0
- package/template/.agent/skills/performance-budgeting/SKILL.md +144 -0
- package/template/.agent/skills/pipeline-rubrics/SKILL.md +51 -0
- package/template/.agent/skills/pipeline-rubrics/references/architecture-rubric.md +19 -0
- package/template/.agent/skills/pipeline-rubrics/references/be-rubric.md +21 -0
- package/template/.agent/skills/pipeline-rubrics/references/fe-rubric.md +20 -0
- package/template/.agent/skills/pipeline-rubrics/references/ia-rubric.md +19 -0
- package/template/.agent/skills/pipeline-rubrics/references/scoring.md +28 -0
- package/template/.agent/skills/pipeline-rubrics/references/vision-rubric.md +11 -0
- package/template/.agent/skills/prd-templates/SKILL.md +88 -0
- package/template/.agent/skills/prd-templates/references/architecture-design-template.md +88 -0
- package/template/.agent/skills/prd-templates/references/be-spec-template.md +101 -0
- package/template/.agent/skills/prd-templates/references/data-placement-template.md +74 -0
- package/template/.agent/skills/prd-templates/references/decomposition-templates.md +211 -0
- package/template/.agent/skills/prd-templates/references/design-system-decisions.md +198 -0
- package/template/.agent/skills/prd-templates/references/engineering-standards-template.md +124 -0
- package/template/.agent/skills/prd-templates/references/fe-classification-procedures.md +47 -0
- package/template/.agent/skills/prd-templates/references/fe-spec-template.md +84 -0
- package/template/.agent/skills/prd-templates/references/infrastructure-report-template.md +71 -0
- package/template/.agent/skills/prd-templates/references/operational-templates.md +116 -0
- package/template/.agent/skills/prd-templates/references/placeholder-guard-template.md +21 -0
- package/template/.agent/skills/prd-templates/references/surface-model.md +61 -0
- package/template/.agent/skills/prd-templates/references/vision-template.md +66 -0
- package/template/.agent/skills/prompt-engineer/README.md +659 -0
- package/template/.agent/skills/prompt-engineer/SKILL.md +249 -0
- package/template/.agent/skills/regex-patterns/SKILL.md +751 -0
- package/template/.agent/skills/resolve-ambiguity/SKILL.md +278 -0
- package/template/.agent/skills/rest-api-design/SKILL.md +478 -0
- package/template/.agent/skills/security-scanning-security-hardening/SKILL.md +231 -0
- package/template/.agent/skills/session-continuity/SKILL.md +730 -0
- package/template/.agent/skills/session-continuity/protocols/01-session-resumption.md +38 -0
- package/template/.agent/skills/session-continuity/protocols/02-progress-generation.md +85 -0
- package/template/.agent/skills/session-continuity/protocols/03-progress-update.md +70 -0
- package/template/.agent/skills/session-continuity/protocols/04-pattern-extraction.md +60 -0
- package/template/.agent/skills/session-continuity/protocols/05-session-close.md +37 -0
- package/template/.agent/skills/session-continuity/protocols/06-decision-analysis.md +84 -0
- package/template/.agent/skills/session-continuity/protocols/07-spec-pipeline-generation.md +48 -0
- package/template/.agent/skills/session-continuity/protocols/08-spec-pipeline-update.md +43 -0
- package/template/.agent/skills/session-continuity/protocols/09-parallel-claim.md +122 -0
- package/template/.agent/skills/session-continuity/protocols/10-placeholder-verification-gate.md +104 -0
- package/template/.agent/skills/session-continuity/protocols/ambiguity-gates.md +48 -0
- package/template/.agent/skills/skill-creator/LICENSE.txt +202 -0
- package/template/.agent/skills/skill-creator/README.md +270 -0
- package/template/.agent/skills/skill-creator/SKILL.md +590 -0
- package/template/.agent/skills/skill-creator/references/output-patterns.md +82 -0
- package/template/.agent/skills/skill-creator/references/workflows.md +28 -0
- package/template/.agent/skills/skill-creator/scripts/init_skill.py +303 -0
- package/template/.agent/skills/skill-creator/scripts/package_skill.py +110 -0
- package/template/.agent/skills/skill-creator/scripts/quick_validate.py +95 -0
- package/template/.agent/skills/spec-writing/SKILL.md +110 -0
- package/template/.agent/skills/systematic-debugging/CREATION-LOG.md +119 -0
- package/template/.agent/skills/systematic-debugging/SKILL.md +297 -0
- package/template/.agent/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
- package/template/.agent/skills/systematic-debugging/condition-based-waiting.md +115 -0
- package/template/.agent/skills/systematic-debugging/defense-in-depth.md +122 -0
- package/template/.agent/skills/systematic-debugging/find-polluter.sh +63 -0
- package/template/.agent/skills/systematic-debugging/root-cause-tracing.md +169 -0
- package/template/.agent/skills/systematic-debugging/test-academic.md +14 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/template/.agent/skills/tdd-workflow/SKILL.md +409 -0
- package/template/.agent/skills/tech-stack-catalog/SKILL.md +49 -0
- package/template/.agent/skills/tech-stack-catalog/references/constraint-questions.md +21 -0
- package/template/.agent/skills/tech-stack-catalog/references/dev-tooling-decisions.md +37 -0
- package/template/.agent/skills/tech-stack-catalog/references/surface-decision-tables.md +69 -0
- package/template/.agent/skills/technical-writer/SKILL.md +242 -0
- package/template/.agent/skills/testing-strategist/SKILL.md +932 -0
- package/template/.agent/skills/verification-before-completion/SKILL.md +145 -0
- package/template/.agent/skills/workflow-automation/SKILL.md +73 -0
- package/template/.agent/workflows/audit-ambiguity-execute.md +165 -0
- package/template/.agent/workflows/audit-ambiguity-rubrics.md +83 -0
- package/template/.agent/workflows/audit-ambiguity.md +64 -0
- package/template/.agent/workflows/bootstrap-agents-fill.md +201 -0
- package/template/.agent/workflows/bootstrap-agents-provision.md +197 -0
- package/template/.agent/workflows/bootstrap-agents.md +66 -0
- package/template/.agent/workflows/create-prd-architecture.md +119 -0
- package/template/.agent/workflows/create-prd-compile.md +138 -0
- package/template/.agent/workflows/create-prd-design-system.md +135 -0
- package/template/.agent/workflows/create-prd-security.md +113 -0
- package/template/.agent/workflows/create-prd-stack.md +91 -0
- package/template/.agent/workflows/create-prd.md +168 -0
- package/template/.agent/workflows/decompose-architecture-structure.md +82 -0
- package/template/.agent/workflows/decompose-architecture-validate.md +119 -0
- package/template/.agent/workflows/decompose-architecture.md +111 -0
- package/template/.agent/workflows/evolve-contract.md +98 -0
- package/template/.agent/workflows/evolve-feature-cascade.md +140 -0
- package/template/.agent/workflows/evolve-feature-classify.md +116 -0
- package/template/.agent/workflows/evolve-feature.md +56 -0
- package/template/.agent/workflows/ideate-discover.md +144 -0
- package/template/.agent/workflows/ideate-extract.md +129 -0
- package/template/.agent/workflows/ideate-validate.md +117 -0
- package/template/.agent/workflows/ideate.md +113 -0
- package/template/.agent/workflows/implement-slice-setup.md +113 -0
- package/template/.agent/workflows/implement-slice-tdd.md +198 -0
- package/template/.agent/workflows/implement-slice.md +50 -0
- package/template/.agent/workflows/plan-phase.md +202 -0
- package/template/.agent/workflows/propagate-decision-apply.md +135 -0
- package/template/.agent/workflows/propagate-decision-scan.md +147 -0
- package/template/.agent/workflows/propagate-decision.md +56 -0
- package/template/.agent/workflows/remediate-pipeline-assess.md +138 -0
- package/template/.agent/workflows/remediate-pipeline-execute.md +135 -0
- package/template/.agent/workflows/remediate-pipeline.md +55 -0
- package/template/.agent/workflows/resolve-ambiguity.md +82 -0
- package/template/.agent/workflows/sync-kit.md +209 -0
- package/template/.agent/workflows/update-architecture-map.md +74 -0
- package/template/.agent/workflows/validate-phase.md +219 -0
- package/template/.agent/workflows/verify-infrastructure.md +207 -0
- package/template/.agent/workflows/write-architecture-spec-deepen.md +139 -0
- package/template/.agent/workflows/write-architecture-spec-design.md +202 -0
- package/template/.agent/workflows/write-architecture-spec.md +63 -0
- package/template/.agent/workflows/write-be-spec-classify.md +165 -0
- package/template/.agent/workflows/write-be-spec-write.md +98 -0
- package/template/.agent/workflows/write-be-spec.md +76 -0
- package/template/.agent/workflows/write-fe-spec-classify.md +170 -0
- package/template/.agent/workflows/write-fe-spec-write.md +94 -0
- package/template/.agent/workflows/write-fe-spec.md +71 -0
- package/template/AGENTS.md +176 -0
- package/template/GEMINI.md +177 -0
- package/template/docs/README.md +187 -0
- package/template/docs/audits/.gitkeep +0 -0
- package/template/docs/audits/README.md +10 -0
- package/template/docs/plans/.gitkeep +0 -0
- package/template/docs/plans/README.md +21 -0
- package/template/docs/plans/be/.gitkeep +0 -0
- package/template/docs/plans/be/README.md +11 -0
- package/template/docs/plans/fe/.gitkeep +0 -0
- package/template/docs/plans/fe/README.md +11 -0
- package/template/docs/plans/ia/.gitkeep +0 -0
- package/template/docs/plans/ia/README.md +17 -0
- package/template/docs/plans/ia/deep-dives/.gitkeep +0 -0
- package/template/docs/plans/ia/deep-dives/README.md +5 -0
- package/template/docs/plans/phases/.gitkeep +0 -0
- package/template/docs/plans/phases/README.md +11 -0
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: input-sanitization
|
|
3
|
+
description: "Input validation and sanitization patterns: server-side validation as source of truth, Zod/Joi/Yup schema validation, SQL parameterization, HTML sanitization, file upload validation, URL/email validation, path traversal prevention, command injection prevention, ReDoS prevention, and content-type enforcement. Use when handling any user input in web applications."
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Input Validation and Sanitization
|
|
8
|
+
|
|
9
|
+
**Status**: Production Ready
|
|
10
|
+
**Last Updated**: 2026-02-17
|
|
11
|
+
**Dependencies**: None (standalone skill)
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Use This Skill When
|
|
16
|
+
|
|
17
|
+
- Handling any form of user input in a web application
|
|
18
|
+
- Building API endpoints that accept request bodies, query params, or headers
|
|
19
|
+
- Implementing file upload functionality
|
|
20
|
+
- Preventing injection attacks (SQL, NoSQL, command, XSS, path traversal)
|
|
21
|
+
|
|
22
|
+
## Do Not Use This Skill When
|
|
23
|
+
|
|
24
|
+
- You need cryptographic operations (use crypto-patterns skill)
|
|
25
|
+
- You need CSP/CORS configuration (use csp-cors-headers skill)
|
|
26
|
+
- You need dependency security scanning (use dependency-auditing skill)
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Core Principle
|
|
31
|
+
|
|
32
|
+
Client-side validation is for UX. Server-side validation is for security.
|
|
33
|
+
Both are required. Neither replaces the other. Share the same schema.
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
// src/schemas/user.schema.ts -- shared between client and server
|
|
37
|
+
import { z } from "zod";
|
|
38
|
+
|
|
39
|
+
export const CreateUserSchema = z.object({
|
|
40
|
+
email: z.string().email().max(255).toLowerCase().trim(),
|
|
41
|
+
password: z.string().min(8).max(128),
|
|
42
|
+
displayName: z.string().min(1).max(50).trim(),
|
|
43
|
+
age: z.number().int().min(13).max(150),
|
|
44
|
+
});
|
|
45
|
+
export type CreateUserInput = z.infer<typeof CreateUserSchema>;
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
// Server-side: validate EVERY request
|
|
50
|
+
app.post("/api/users", async (req, res) => {
|
|
51
|
+
const parsed = CreateUserSchema.safeParse(req.body);
|
|
52
|
+
if (!parsed.success) {
|
|
53
|
+
return res.status(400).json({
|
|
54
|
+
error: "Validation failed",
|
|
55
|
+
issues: parsed.error.issues.map((i) => ({ field: i.path.join("."), message: i.message })),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
const user = await createUser(parsed.data);
|
|
59
|
+
res.status(201).json(user);
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Schema Validation Libraries
|
|
66
|
+
|
|
67
|
+
### Zod (Recommended for TypeScript)
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
const ProductSchema = z.object({
|
|
71
|
+
name: z.string().min(1).max(200).trim(),
|
|
72
|
+
price: z.number().positive().multipleOf(0.01),
|
|
73
|
+
category: z.enum(["electronics", "clothing", "food", "books"]),
|
|
74
|
+
tags: z.array(z.string().max(50)).max(10).default([]),
|
|
75
|
+
metadata: z.record(z.string(), z.string()).optional(),
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const UpdateProductSchema = ProductSchema.partial(); // All fields optional
|
|
79
|
+
const DateRangeSchema = z.object({
|
|
80
|
+
startDate: z.string().datetime(),
|
|
81
|
+
endDate: z.string().datetime(),
|
|
82
|
+
}).refine(
|
|
83
|
+
(d) => new Date(d.endDate) > new Date(d.startDate),
|
|
84
|
+
{ message: "End date must be after start date", path: ["endDate"] }
|
|
85
|
+
);
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Joi
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
import Joi from "joi";
|
|
92
|
+
const schema = Joi.object({
|
|
93
|
+
name: Joi.string().min(1).max(200).trim().required(),
|
|
94
|
+
price: Joi.number().positive().precision(2).required(),
|
|
95
|
+
});
|
|
96
|
+
const { error, value } = schema.validate(req.body, { abortEarly: false, stripUnknown: true });
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Pydantic (Python)
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from pydantic import BaseModel, Field, field_validator
|
|
103
|
+
|
|
104
|
+
class CreateProduct(BaseModel):
|
|
105
|
+
name: str = Field(min_length=1, max_length=200)
|
|
106
|
+
price: float = Field(gt=0)
|
|
107
|
+
category: str
|
|
108
|
+
|
|
109
|
+
@field_validator("name")
|
|
110
|
+
@classmethod
|
|
111
|
+
def strip_name(cls, v: str) -> str:
|
|
112
|
+
return v.strip()
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## SQL Parameterization
|
|
118
|
+
|
|
119
|
+
Never concatenate user input into SQL strings.
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
// VULNERABLE
|
|
123
|
+
const query = `SELECT * FROM users WHERE email = '${email}'`;
|
|
124
|
+
|
|
125
|
+
// SECURE: Parameterized query (Node.js pg)
|
|
126
|
+
const result = await pool.query("SELECT * FROM users WHERE email = $1", [email]);
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
# VULNERABLE
|
|
131
|
+
cursor.execute(f"SELECT * FROM users WHERE email = '{email}'")
|
|
132
|
+
|
|
133
|
+
# SECURE: Parameterized query (psycopg2)
|
|
134
|
+
cursor.execute("SELECT * FROM users WHERE email = %s", (email,))
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
```go
|
|
138
|
+
// SECURE: Parameterized query (database/sql)
|
|
139
|
+
row := db.QueryRowContext(ctx, "SELECT id FROM users WHERE email = $1", email)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**ORM warning**: Even with ORMs, avoid raw queries with interpolation:
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
// VULNERABLE
|
|
146
|
+
await prisma.$queryRawUnsafe(`SELECT * FROM users WHERE name = '${name}'`);
|
|
147
|
+
// SECURE
|
|
148
|
+
await prisma.$queryRaw`SELECT * FROM users WHERE name = ${name}`;
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## HTML Sanitization
|
|
154
|
+
|
|
155
|
+
When accepting HTML input (rich text editors), sanitize to remove dangerous elements.
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
import createDOMPurify from "dompurify";
|
|
159
|
+
import { JSDOM } from "jsdom";
|
|
160
|
+
|
|
161
|
+
const DOMPurify = createDOMPurify(new JSDOM("").window);
|
|
162
|
+
|
|
163
|
+
function sanitizeHTML(dirty: string): string {
|
|
164
|
+
return DOMPurify.sanitize(dirty, {
|
|
165
|
+
ALLOWED_TAGS: ["h1", "h2", "h3", "p", "br", "ul", "ol", "li",
|
|
166
|
+
"b", "i", "em", "strong", "a", "img", "blockquote", "pre", "code"],
|
|
167
|
+
ALLOWED_ATTR: ["href", "src", "alt", "title", "class"],
|
|
168
|
+
ALLOW_DATA_ATTR: false,
|
|
169
|
+
FORBID_TAGS: ["script", "style", "iframe", "form", "input"],
|
|
170
|
+
FORBID_ATTR: ["onerror", "onclick", "onload", "style"],
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Force safe link behavior
|
|
175
|
+
DOMPurify.addHook("afterSanitizeAttributes", (node) => {
|
|
176
|
+
if (node.tagName === "A") {
|
|
177
|
+
node.setAttribute("target", "_blank");
|
|
178
|
+
node.setAttribute("rel", "noopener noreferrer");
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### React XSS Prevention
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
// SAFE: React auto-escapes
|
|
187
|
+
function Comment({ text }: { text: string }) { return <p>{text}</p>; }
|
|
188
|
+
|
|
189
|
+
// DANGEROUS: dangerouslySetInnerHTML bypasses escaping
|
|
190
|
+
<div dangerouslySetInnerHTML={{ __html: userHtml }} /> // XSS risk
|
|
191
|
+
|
|
192
|
+
// SAFE: Sanitize first
|
|
193
|
+
<div dangerouslySetInnerHTML={{ __html: sanitizeHTML(userHtml) }} />
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## File Upload Validation
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
import fileType from "file-type";
|
|
202
|
+
import path from "path";
|
|
203
|
+
|
|
204
|
+
const ALLOWED_TYPES = new Map([
|
|
205
|
+
["image/jpeg", { extensions: [".jpg", ".jpeg"], maxSize: 5 * 1024 * 1024 }],
|
|
206
|
+
["image/png", { extensions: [".png"], maxSize: 5 * 1024 * 1024 }],
|
|
207
|
+
["application/pdf", { extensions: [".pdf"], maxSize: 10 * 1024 * 1024 }],
|
|
208
|
+
]);
|
|
209
|
+
|
|
210
|
+
async function validateUpload(buffer: Buffer, originalName: string, declaredMime: string) {
|
|
211
|
+
const config = ALLOWED_TYPES.get(declaredMime);
|
|
212
|
+
if (!config) return { valid: false, error: "File type not allowed" };
|
|
213
|
+
|
|
214
|
+
const ext = path.extname(originalName).toLowerCase();
|
|
215
|
+
if (!config.extensions.includes(ext)) return { valid: false, error: "Extension mismatch" };
|
|
216
|
+
if (buffer.length > config.maxSize) return { valid: false, error: "File too large" };
|
|
217
|
+
|
|
218
|
+
// Verify magic bytes (actual content, not just declared MIME)
|
|
219
|
+
const detected = await fileType.fromBuffer(buffer);
|
|
220
|
+
if (!detected || detected.mime !== declaredMime)
|
|
221
|
+
return { valid: false, error: "Content does not match declared type" };
|
|
222
|
+
|
|
223
|
+
if (originalName.includes("\0")) return { valid: false, error: "Invalid filename" };
|
|
224
|
+
return { valid: true };
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
// Express multer configuration with strict limits
|
|
230
|
+
import multer from "multer";
|
|
231
|
+
const upload = multer({
|
|
232
|
+
storage: multer.memoryStorage(),
|
|
233
|
+
limits: { fileSize: 10 * 1024 * 1024, files: 5, fields: 10 },
|
|
234
|
+
fileFilter: (req, file, cb) => {
|
|
235
|
+
if (!ALLOWED_TYPES.has(file.mimetype)) { cb(new Error("Type not allowed")); return; }
|
|
236
|
+
cb(null, true);
|
|
237
|
+
},
|
|
238
|
+
});
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## URL Validation
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
function validateUrl(input: string): { valid: boolean; error?: string } {
|
|
247
|
+
let parsed: URL;
|
|
248
|
+
try { parsed = new URL(input); } catch { return { valid: false, error: "Invalid URL" }; }
|
|
249
|
+
|
|
250
|
+
if (!["http:", "https:"].includes(parsed.protocol))
|
|
251
|
+
return { valid: false, error: "Only HTTP(S) allowed" };
|
|
252
|
+
if (/^(\d{1,3}\.){3}\d{1,3}$/.test(parsed.hostname))
|
|
253
|
+
return { valid: false, error: "IP addresses not allowed" };
|
|
254
|
+
if (["localhost", "127.0.0.1", "0.0.0.0"].includes(parsed.hostname))
|
|
255
|
+
return { valid: false, error: "Internal hosts not allowed" };
|
|
256
|
+
if (input.length > 2048) return { valid: false, error: "URL too long" };
|
|
257
|
+
return { valid: true };
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## Email Validation
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
// Use Zod -- do NOT write custom email regex
|
|
267
|
+
const EmailSchema = z.string().email().max(254).toLowerCase().trim();
|
|
268
|
+
|
|
269
|
+
// Stricter for registration (block disposable domains)
|
|
270
|
+
const RegistrationEmailSchema = z.string().email().max(254).toLowerCase().trim()
|
|
271
|
+
.refine((email) => {
|
|
272
|
+
const blocked = ["mailinator.com", "guerrillamail.com", "tempmail.com"];
|
|
273
|
+
return !blocked.includes(email.split("@")[1]);
|
|
274
|
+
}, { message: "Disposable email addresses not allowed" });
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## Path Traversal Prevention
|
|
280
|
+
|
|
281
|
+
```typescript
|
|
282
|
+
import path from "path";
|
|
283
|
+
|
|
284
|
+
const UPLOAD_DIR = "/var/app/uploads";
|
|
285
|
+
|
|
286
|
+
// VULNERABLE: Direct path concatenation
|
|
287
|
+
app.get("/files/:filename", (req, res) => res.sendFile(`${UPLOAD_DIR}/${req.params.filename}`));
|
|
288
|
+
|
|
289
|
+
// SECURE: Resolve and validate containment
|
|
290
|
+
app.get("/files/:filename", async (req, res) => {
|
|
291
|
+
const filename = req.params.filename;
|
|
292
|
+
if (/[\/\\]/.test(filename) || filename.includes("..") || filename.includes("\0"))
|
|
293
|
+
return res.status(400).json({ error: "Invalid filename" });
|
|
294
|
+
|
|
295
|
+
const resolved = path.resolve(UPLOAD_DIR, filename);
|
|
296
|
+
if (!resolved.startsWith(path.resolve(UPLOAD_DIR) + path.sep))
|
|
297
|
+
return res.status(400).json({ error: "Invalid path" });
|
|
298
|
+
|
|
299
|
+
res.sendFile(resolved);
|
|
300
|
+
});
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
```python
|
|
304
|
+
from pathlib import Path
|
|
305
|
+
UPLOAD_DIR = Path("/var/app/uploads").resolve()
|
|
306
|
+
|
|
307
|
+
def safe_path(filename: str) -> Path:
|
|
308
|
+
if ".." in filename or "\x00" in filename:
|
|
309
|
+
raise ValueError("Invalid filename")
|
|
310
|
+
resolved = (UPLOAD_DIR / filename).resolve()
|
|
311
|
+
if not str(resolved).startswith(str(UPLOAD_DIR) + "/"):
|
|
312
|
+
raise ValueError("Path traversal detected")
|
|
313
|
+
return resolved
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## Command Injection Prevention
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
import { execFile } from "child_process";
|
|
322
|
+
import { promisify } from "util";
|
|
323
|
+
|
|
324
|
+
const execFileAsync = promisify(execFile);
|
|
325
|
+
const FilenameSchema = z.string().regex(/^[a-zA-Z0-9_.-]+$/).max(255);
|
|
326
|
+
|
|
327
|
+
// VULNERABLE: exec() interprets shell metacharacters
|
|
328
|
+
exec(`convert ${inputFile} ${outputFile}`);
|
|
329
|
+
|
|
330
|
+
// SECURE: execFile passes arguments directly, no shell
|
|
331
|
+
async function convertImage(input: string, output: string) {
|
|
332
|
+
FilenameSchema.parse(input);
|
|
333
|
+
FilenameSchema.parse(output);
|
|
334
|
+
await execFileAsync("convert", [input, output], { timeout: 30000, cwd: "/var/app/uploads" });
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
```python
|
|
339
|
+
# VULNERABLE
|
|
340
|
+
os.system(f"convert {input_file} {output_file}")
|
|
341
|
+
|
|
342
|
+
# SECURE: subprocess with argument list, no shell=True
|
|
343
|
+
subprocess.run(["convert", input_file, output_file], check=True, timeout=30)
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
## ReDoS Prevention
|
|
349
|
+
|
|
350
|
+
Certain regex patterns cause exponential backtracking with crafted input.
|
|
351
|
+
|
|
352
|
+
```typescript
|
|
353
|
+
// VULNERABLE: Nested quantifiers
|
|
354
|
+
const emailRegex = /^([a-zA-Z0-9]+)*@[a-zA-Z0-9]+\.[a-zA-Z]+$/;
|
|
355
|
+
// Input "aaaaaaaaaaaaaaaaaa!" will hang
|
|
356
|
+
|
|
357
|
+
// SAFE: Use built-in validators
|
|
358
|
+
import { z } from "zod";
|
|
359
|
+
const email = z.string().email(); // Uses safe internal pattern
|
|
360
|
+
|
|
361
|
+
// SAFE: Use URL constructor instead of regex
|
|
362
|
+
function isValidUrl(input: string): boolean {
|
|
363
|
+
try { new URL(input); return true; } catch { return false; }
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
**Prevention rules**: Avoid nested quantifiers `(a+)+`, avoid overlapping
|
|
368
|
+
alternatives `(a|a)+`, limit input length before regex, use `safe-regex`
|
|
369
|
+
library to check patterns, prefer built-in validators over custom regex.
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## Content-Type Enforcement
|
|
374
|
+
|
|
375
|
+
```typescript
|
|
376
|
+
// Reject unexpected content types
|
|
377
|
+
const requireJSON: RequestHandler = (req, res, next) => {
|
|
378
|
+
if (["GET", "DELETE"].includes(req.method)) return next();
|
|
379
|
+
if (!req.headers["content-type"]?.includes("application/json"))
|
|
380
|
+
return res.status(415).json({ error: "Content-Type must be application/json" });
|
|
381
|
+
next();
|
|
382
|
+
};
|
|
383
|
+
app.use("/api/", requireJSON);
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
## Anti-Patterns Summary
|
|
389
|
+
|
|
390
|
+
| Anti-Pattern | Risk | Fix |
|
|
391
|
+
|-------------|------|-----|
|
|
392
|
+
| Client-side only validation | Trivially bypassed | Always validate server-side |
|
|
393
|
+
| String concatenation in SQL | SQL injection | Parameterized queries |
|
|
394
|
+
| `innerHTML` with user data | XSS | textContent or DOMPurify |
|
|
395
|
+
| Direct file path from user input | Path traversal | Resolve + containment check |
|
|
396
|
+
| `exec()` with user input | Command injection | `execFile()` with arg array |
|
|
397
|
+
| Custom email regex | ReDoS, false negatives | Use Zod/validator.js |
|
|
398
|
+
| Trusting Content-Type header | Type confusion | Verify magic bytes for files |
|
|
399
|
+
| No file size limits | DoS via large uploads | multer/busboy limits |
|
|
400
|
+
| Nested regex quantifiers | ReDoS | safe-regex check, limit input length |
|
|
401
|
+
| Trusting `req.params` directly | Injection, traversal | Validate with Zod schema |
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
## Validation Checklist
|
|
406
|
+
|
|
407
|
+
- [ ] Every API endpoint validates input with a schema library
|
|
408
|
+
- [ ] SQL queries use parameterized statements
|
|
409
|
+
- [ ] HTML user content is sanitized with DOMPurify or sanitize-html
|
|
410
|
+
- [ ] File uploads validate MIME type, magic bytes, extension, and size
|
|
411
|
+
- [ ] URLs validated for protocol, host, and length
|
|
412
|
+
- [ ] File paths resolved and checked for directory containment
|
|
413
|
+
- [ ] Shell commands use argument arrays, not string interpolation
|
|
414
|
+
- [ ] Regular expressions checked for ReDoS vulnerability
|
|
415
|
+
- [ ] Content-Type headers enforced on API endpoints
|
|
416
|
+
- [ ] Client and server use the same validation schema
|
|
417
|
+
|
|
418
|
+
---
|
|
419
|
+
|
|
420
|
+
## References
|
|
421
|
+
|
|
422
|
+
- **OWASP Input Validation Cheat Sheet**: https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html
|
|
423
|
+
- **Zod Documentation**: https://zod.dev/
|
|
424
|
+
- **DOMPurify**: https://github.com/cure53/DOMPurify
|
|
425
|
+
- **OWASP File Upload Cheat Sheet**: https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html
|
|
426
|
+
- **OWASP SQL Injection Prevention**: https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
430
|
+
**Last verified**: 2026-02-17 | **Skill version**: 1.0.0
|