@raishin/vanguard-frontier-agentic 3.2.0 → 3.4.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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +22 -1
- package/.cursor-plugin/plugin.json +22 -1
- package/.github/plugin/marketplace.json +1 -1
- package/README.md +33 -15
- package/agents/cross-functional/revenue-critical-journey-integrity-agent/AGENT.md +112 -0
- package/agents/cross-functional/revenue-critical-journey-integrity-agent/harnesses/claude-code.agent.md +111 -0
- package/agents/cross-functional/revenue-critical-journey-integrity-agent/harnesses/codex.toml +37 -0
- package/agents/cross-functional/revenue-critical-journey-integrity-agent/harnesses/copilot.agent.md +120 -0
- package/agents/cross-functional/revenue-critical-journey-integrity-agent/harnesses/cursor.agent.md +112 -0
- package/agents/cross-functional/revenue-critical-journey-integrity-agent/harnesses/gemini.agent.md +112 -0
- package/agents/cross-functional/revenue-critical-journey-integrity-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/cross-functional/revenue-critical-journey-integrity-agent/harnesses/kiro-ide.agent.md +111 -0
- package/agents/cross-functional/revenue-critical-journey-integrity-agent/metadata.json +42 -0
- package/agents/java/README.md +73 -0
- package/agents/java/java-application-server-exit-agent/AGENT.md +59 -0
- package/agents/java/java-application-server-exit-agent/harnesses/claude-code.agent.md +42 -0
- package/agents/java/java-application-server-exit-agent/harnesses/codex.toml +40 -0
- package/agents/java/java-application-server-exit-agent/harnesses/copilot.agent.md +42 -0
- package/agents/java/java-application-server-exit-agent/harnesses/cursor.agent.md +42 -0
- package/agents/java/java-application-server-exit-agent/harnesses/gemini.agent.md +42 -0
- package/agents/java/java-application-server-exit-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-application-server-exit-agent/harnesses/kiro-ide.agent.md +42 -0
- package/agents/java/java-application-server-exit-agent/metadata.json +41 -0
- package/agents/java/java-concurrency-and-virtual-thread-agent/AGENT.md +59 -0
- package/agents/java/java-concurrency-and-virtual-thread-agent/harnesses/claude-code.agent.md +42 -0
- package/agents/java/java-concurrency-and-virtual-thread-agent/harnesses/codex.toml +40 -0
- package/agents/java/java-concurrency-and-virtual-thread-agent/harnesses/copilot.agent.md +42 -0
- package/agents/java/java-concurrency-and-virtual-thread-agent/harnesses/cursor.agent.md +42 -0
- package/agents/java/java-concurrency-and-virtual-thread-agent/harnesses/gemini.agent.md +42 -0
- package/agents/java/java-concurrency-and-virtual-thread-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-concurrency-and-virtual-thread-agent/harnesses/kiro-ide.agent.md +42 -0
- package/agents/java/java-concurrency-and-virtual-thread-agent/metadata.json +41 -0
- package/agents/java/java-container-and-kubernetes-readiness-agent/AGENT.md +59 -0
- package/agents/java/java-container-and-kubernetes-readiness-agent/harnesses/claude-code.agent.md +42 -0
- package/agents/java/java-container-and-kubernetes-readiness-agent/harnesses/codex.toml +40 -0
- package/agents/java/java-container-and-kubernetes-readiness-agent/harnesses/copilot.agent.md +42 -0
- package/agents/java/java-container-and-kubernetes-readiness-agent/harnesses/cursor.agent.md +42 -0
- package/agents/java/java-container-and-kubernetes-readiness-agent/harnesses/gemini.agent.md +42 -0
- package/agents/java/java-container-and-kubernetes-readiness-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-container-and-kubernetes-readiness-agent/harnesses/kiro-ide.agent.md +42 -0
- package/agents/java/java-container-and-kubernetes-readiness-agent/metadata.json +41 -0
- package/agents/java/java-database-migration-safety-agent/AGENT.md +59 -0
- package/agents/java/java-database-migration-safety-agent/harnesses/claude-code.agent.md +42 -0
- package/agents/java/java-database-migration-safety-agent/harnesses/codex.toml +40 -0
- package/agents/java/java-database-migration-safety-agent/harnesses/copilot.agent.md +42 -0
- package/agents/java/java-database-migration-safety-agent/harnesses/cursor.agent.md +42 -0
- package/agents/java/java-database-migration-safety-agent/harnesses/gemini.agent.md +42 -0
- package/agents/java/java-database-migration-safety-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-database-migration-safety-agent/harnesses/kiro-ide.agent.md +42 -0
- package/agents/java/java-database-migration-safety-agent/metadata.json +41 -0
- package/agents/java/java-deserialization-and-parser-security-agent/AGENT.md +57 -0
- package/agents/java/java-deserialization-and-parser-security-agent/harnesses/claude-code.agent.md +40 -0
- package/agents/java/java-deserialization-and-parser-security-agent/harnesses/codex.toml +37 -0
- package/agents/java/java-deserialization-and-parser-security-agent/harnesses/copilot.agent.md +40 -0
- package/agents/java/java-deserialization-and-parser-security-agent/harnesses/cursor.agent.md +40 -0
- package/agents/java/java-deserialization-and-parser-security-agent/harnesses/gemini.agent.md +40 -0
- package/agents/java/java-deserialization-and-parser-security-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-deserialization-and-parser-security-agent/harnesses/kiro-ide.agent.md +40 -0
- package/agents/java/java-deserialization-and-parser-security-agent/metadata.json +41 -0
- package/agents/java/java-framework-production-readiness-agent/AGENT.md +57 -0
- package/agents/java/java-framework-production-readiness-agent/harnesses/claude-code.agent.md +40 -0
- package/agents/java/java-framework-production-readiness-agent/harnesses/codex.toml +39 -0
- package/agents/java/java-framework-production-readiness-agent/harnesses/copilot.agent.md +40 -0
- package/agents/java/java-framework-production-readiness-agent/harnesses/cursor.agent.md +40 -0
- package/agents/java/java-framework-production-readiness-agent/harnesses/gemini.agent.md +40 -0
- package/agents/java/java-framework-production-readiness-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-framework-production-readiness-agent/harnesses/kiro-ide.agent.md +40 -0
- package/agents/java/java-framework-production-readiness-agent/metadata.json +41 -0
- package/agents/java/java-jdk-lifecycle-and-upgrade-agent/AGENT.md +55 -0
- package/agents/java/java-jdk-lifecycle-and-upgrade-agent/harnesses/claude-code.agent.md +38 -0
- package/agents/java/java-jdk-lifecycle-and-upgrade-agent/harnesses/codex.toml +37 -0
- package/agents/java/java-jdk-lifecycle-and-upgrade-agent/harnesses/copilot.agent.md +38 -0
- package/agents/java/java-jdk-lifecycle-and-upgrade-agent/harnesses/cursor.agent.md +38 -0
- package/agents/java/java-jdk-lifecycle-and-upgrade-agent/harnesses/gemini.agent.md +38 -0
- package/agents/java/java-jdk-lifecycle-and-upgrade-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-jdk-lifecycle-and-upgrade-agent/harnesses/kiro-ide.agent.md +38 -0
- package/agents/java/java-jdk-lifecycle-and-upgrade-agent/metadata.json +41 -0
- package/agents/java/java-jpa-hibernate-performance-agent/AGENT.md +57 -0
- package/agents/java/java-jpa-hibernate-performance-agent/harnesses/claude-code.agent.md +40 -0
- package/agents/java/java-jpa-hibernate-performance-agent/harnesses/codex.toml +38 -0
- package/agents/java/java-jpa-hibernate-performance-agent/harnesses/copilot.agent.md +40 -0
- package/agents/java/java-jpa-hibernate-performance-agent/harnesses/cursor.agent.md +40 -0
- package/agents/java/java-jpa-hibernate-performance-agent/harnesses/gemini.agent.md +40 -0
- package/agents/java/java-jpa-hibernate-performance-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-jpa-hibernate-performance-agent/harnesses/kiro-ide.agent.md +40 -0
- package/agents/java/java-jpa-hibernate-performance-agent/metadata.json +41 -0
- package/agents/java/java-jvm-performance-and-gc-agent/AGENT.md +60 -0
- package/agents/java/java-jvm-performance-and-gc-agent/harnesses/claude-code.agent.md +43 -0
- package/agents/java/java-jvm-performance-and-gc-agent/harnesses/codex.toml +40 -0
- package/agents/java/java-jvm-performance-and-gc-agent/harnesses/copilot.agent.md +43 -0
- package/agents/java/java-jvm-performance-and-gc-agent/harnesses/cursor.agent.md +43 -0
- package/agents/java/java-jvm-performance-and-gc-agent/harnesses/gemini.agent.md +43 -0
- package/agents/java/java-jvm-performance-and-gc-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-jvm-performance-and-gc-agent/harnesses/kiro-ide.agent.md +43 -0
- package/agents/java/java-jvm-performance-and-gc-agent/metadata.json +41 -0
- package/agents/java/java-kafka-reliability-agent/AGENT.md +60 -0
- package/agents/java/java-kafka-reliability-agent/harnesses/claude-code.agent.md +43 -0
- package/agents/java/java-kafka-reliability-agent/harnesses/codex.toml +40 -0
- package/agents/java/java-kafka-reliability-agent/harnesses/copilot.agent.md +43 -0
- package/agents/java/java-kafka-reliability-agent/harnesses/cursor.agent.md +43 -0
- package/agents/java/java-kafka-reliability-agent/harnesses/gemini.agent.md +43 -0
- package/agents/java/java-kafka-reliability-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-kafka-reliability-agent/harnesses/kiro-ide.agent.md +43 -0
- package/agents/java/java-kafka-reliability-agent/metadata.json +40 -0
- package/agents/java/java-maestro-agent/AGENT.md +51 -0
- package/agents/java/java-maestro-agent/harnesses/claude-code.agent.md +34 -0
- package/agents/java/java-maestro-agent/harnesses/codex.toml +37 -0
- package/agents/java/java-maestro-agent/harnesses/copilot.agent.md +34 -0
- package/agents/java/java-maestro-agent/harnesses/cursor.agent.md +34 -0
- package/agents/java/java-maestro-agent/harnesses/gemini.agent.md +34 -0
- package/agents/java/java-maestro-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-maestro-agent/harnesses/kiro-ide.agent.md +34 -0
- package/agents/java/java-maestro-agent/metadata.json +40 -0
- package/agents/java/java-resilience-pattern-agent/AGENT.md +59 -0
- package/agents/java/java-resilience-pattern-agent/harnesses/claude-code.agent.md +42 -0
- package/agents/java/java-resilience-pattern-agent/harnesses/codex.toml +39 -0
- package/agents/java/java-resilience-pattern-agent/harnesses/copilot.agent.md +42 -0
- package/agents/java/java-resilience-pattern-agent/harnesses/cursor.agent.md +42 -0
- package/agents/java/java-resilience-pattern-agent/harnesses/gemini.agent.md +42 -0
- package/agents/java/java-resilience-pattern-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-resilience-pattern-agent/harnesses/kiro-ide.agent.md +42 -0
- package/agents/java/java-resilience-pattern-agent/metadata.json +42 -0
- package/agents/java/java-spring-security-agent/AGENT.md +59 -0
- package/agents/java/java-spring-security-agent/harnesses/claude-code.agent.md +42 -0
- package/agents/java/java-spring-security-agent/harnesses/codex.toml +39 -0
- package/agents/java/java-spring-security-agent/harnesses/copilot.agent.md +42 -0
- package/agents/java/java-spring-security-agent/harnesses/cursor.agent.md +42 -0
- package/agents/java/java-spring-security-agent/harnesses/gemini.agent.md +42 -0
- package/agents/java/java-spring-security-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-spring-security-agent/harnesses/kiro-ide.agent.md +42 -0
- package/agents/java/java-spring-security-agent/metadata.json +40 -0
- package/agents/java/java-test-architecture-agent/AGENT.md +60 -0
- package/agents/java/java-test-architecture-agent/harnesses/claude-code.agent.md +43 -0
- package/agents/java/java-test-architecture-agent/harnesses/codex.toml +40 -0
- package/agents/java/java-test-architecture-agent/harnesses/copilot.agent.md +43 -0
- package/agents/java/java-test-architecture-agent/harnesses/cursor.agent.md +43 -0
- package/agents/java/java-test-architecture-agent/harnesses/gemini.agent.md +43 -0
- package/agents/java/java-test-architecture-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-test-architecture-agent/harnesses/kiro-ide.agent.md +43 -0
- package/agents/java/java-test-architecture-agent/metadata.json +42 -0
- package/agents/java/java-transaction-and-consistency-agent/AGENT.md +58 -0
- package/agents/java/java-transaction-and-consistency-agent/harnesses/claude-code.agent.md +41 -0
- package/agents/java/java-transaction-and-consistency-agent/harnesses/codex.toml +40 -0
- package/agents/java/java-transaction-and-consistency-agent/harnesses/copilot.agent.md +41 -0
- package/agents/java/java-transaction-and-consistency-agent/harnesses/cursor.agent.md +41 -0
- package/agents/java/java-transaction-and-consistency-agent/harnesses/gemini.agent.md +41 -0
- package/agents/java/java-transaction-and-consistency-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/java/java-transaction-and-consistency-agent/harnesses/kiro-ide.agent.md +41 -0
- package/agents/java/java-transaction-and-consistency-agent/metadata.json +41 -0
- package/agents/php/composer-supply-chain-agent/AGENT.md +114 -0
- package/agents/php/composer-supply-chain-agent/harnesses/claude-code.agent.md +113 -0
- package/agents/php/composer-supply-chain-agent/harnesses/codex.toml +119 -0
- package/agents/php/composer-supply-chain-agent/harnesses/copilot.agent.md +122 -0
- package/agents/php/composer-supply-chain-agent/harnesses/cursor.agent.md +114 -0
- package/agents/php/composer-supply-chain-agent/harnesses/gemini.agent.md +114 -0
- package/agents/php/composer-supply-chain-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/php/composer-supply-chain-agent/harnesses/kiro-ide.agent.md +113 -0
- package/agents/php/composer-supply-chain-agent/metadata.json +31 -0
- package/agents/php/php-application-security-agent/AGENT.md +113 -0
- package/agents/php/php-application-security-agent/harnesses/claude-code.agent.md +112 -0
- package/agents/php/php-application-security-agent/harnesses/codex.toml +118 -0
- package/agents/php/php-application-security-agent/harnesses/copilot.agent.md +121 -0
- package/agents/php/php-application-security-agent/harnesses/cursor.agent.md +113 -0
- package/agents/php/php-application-security-agent/harnesses/gemini.agent.md +113 -0
- package/agents/php/php-application-security-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/php/php-application-security-agent/harnesses/kiro-ide.agent.md +112 -0
- package/agents/php/php-application-security-agent/metadata.json +31 -0
- package/agents/php/php-maestro-agent/AGENT.md +81 -0
- package/agents/php/php-maestro-agent/harnesses/claude-code.agent.md +80 -0
- package/agents/php/php-maestro-agent/harnesses/codex.toml +86 -0
- package/agents/php/php-maestro-agent/harnesses/copilot.agent.md +89 -0
- package/agents/php/php-maestro-agent/harnesses/cursor.agent.md +81 -0
- package/agents/php/php-maestro-agent/harnesses/gemini.agent.md +81 -0
- package/agents/php/php-maestro-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/php/php-maestro-agent/harnesses/kiro-ide.agent.md +80 -0
- package/agents/php/php-maestro-agent/metadata.json +31 -0
- package/agents/php/php-runtime-upgrade-readiness-agent/AGENT.md +117 -0
- package/agents/php/php-runtime-upgrade-readiness-agent/harnesses/claude-code.agent.md +116 -0
- package/agents/php/php-runtime-upgrade-readiness-agent/harnesses/codex.toml +122 -0
- package/agents/php/php-runtime-upgrade-readiness-agent/harnesses/copilot.agent.md +125 -0
- package/agents/php/php-runtime-upgrade-readiness-agent/harnesses/cursor.agent.md +117 -0
- package/agents/php/php-runtime-upgrade-readiness-agent/harnesses/gemini.agent.md +117 -0
- package/agents/php/php-runtime-upgrade-readiness-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/php/php-runtime-upgrade-readiness-agent/harnesses/kiro-ide.agent.md +116 -0
- package/agents/php/php-runtime-upgrade-readiness-agent/metadata.json +30 -0
- package/agents/php/wordpress-security-agent/AGENT.md +107 -0
- package/agents/php/wordpress-security-agent/harnesses/claude-code.agent.md +106 -0
- package/agents/php/wordpress-security-agent/harnesses/codex.toml +112 -0
- package/agents/php/wordpress-security-agent/harnesses/copilot.agent.md +115 -0
- package/agents/php/wordpress-security-agent/harnesses/cursor.agent.md +107 -0
- package/agents/php/wordpress-security-agent/harnesses/gemini.agent.md +107 -0
- package/agents/php/wordpress-security-agent/harnesses/kiro-cli.agent.json +5 -0
- package/agents/php/wordpress-security-agent/harnesses/kiro-ide.agent.md +106 -0
- package/agents/php/wordpress-security-agent/metadata.json +31 -0
- package/catalog/agents.json +609 -0
- package/catalog/asset-integrity.json +1338 -48
- package/catalog/install-roles.json +64 -4
- package/catalog/model-assignments.json +777 -84
- package/catalog/model-policy.json +5 -0
- package/catalog/skill-manifest.json +657 -0
- package/catalog/skills.json +567 -0
- package/package.json +1 -1
- package/plugins/vanguard-frontier-agentic/.codex-plugin/plugin.json +1 -1
- package/powers/README.md +4 -2
- package/powers/vanguard-generic/POWER.md +1 -1
- package/powers/vanguard-java/POWER.md +40 -0
- package/powers/vanguard-php/POWER.md +40 -0
- package/schemas/agent.schema.json +18 -1
- package/schemas/skill.schema.json +27 -1
- package/scripts/generate-docs-data.mjs +1 -1
- package/skills/cross-functional/revenue-critical-journey-integrity-review/SKILL.md +108 -0
- package/skills/cross-functional/revenue-critical-journey-integrity-review/metadata.json +29 -0
- package/skills/cross-functional/revenue-critical-journey-integrity-review/references/idempotency-and-safe-retries.md +155 -0
- package/skills/cross-functional/revenue-critical-journey-integrity-review/references/official-sources.md +71 -0
- package/skills/cross-functional/revenue-critical-journey-integrity-review/references/pci-saq-scope-boundaries.md +118 -0
- package/skills/cross-functional/revenue-critical-journey-integrity-review/references/server-side-revalidation-trust-boundary.md +134 -0
- package/skills/cross-functional/revenue-critical-journey-integrity-review/references/webhook-delivery-dedup-ordering.md +146 -0
- package/skills/cross-functional/revenue-critical-journey-integrity-review/references/workflow-and-output.md +100 -0
- package/skills/java/java-application-server-exit/SKILL.md +59 -0
- package/skills/java/java-application-server-exit/metadata.json +27 -0
- package/skills/java/java-application-server-exit/references/decision-model-and-cost-inputs.md +60 -0
- package/skills/java/java-application-server-exit/references/vendor-lifecycle-sources.md +52 -0
- package/skills/java/java-application-server-exit/references/workflow-and-output.md +102 -0
- package/skills/java/java-concurrency-and-virtual-thread/SKILL.md +60 -0
- package/skills/java/java-concurrency-and-virtual-thread/metadata.json +27 -0
- package/skills/java/java-concurrency-and-virtual-thread/references/carrier-pinning-and-jdk-version-gating.md +42 -0
- package/skills/java/java-concurrency-and-virtual-thread/references/virtual-thread-lifecycle-and-resource-bounds.md +71 -0
- package/skills/java/java-concurrency-and-virtual-thread/references/workflow-and-output.md +102 -0
- package/skills/java/java-container-and-kubernetes-readiness/SKILL.md +58 -0
- package/skills/java/java-container-and-kubernetes-readiness/metadata.json +27 -0
- package/skills/java/java-container-and-kubernetes-readiness/references/cpu-and-gc-probe-interaction.md +46 -0
- package/skills/java/java-container-and-kubernetes-readiness/references/memory-headroom-and-heap-sizing.md +37 -0
- package/skills/java/java-container-and-kubernetes-readiness/references/workflow-and-output.md +103 -0
- package/skills/java/java-database-migration-safety/SKILL.md +58 -0
- package/skills/java/java-database-migration-safety/metadata.json +27 -0
- package/skills/java/java-database-migration-safety/references/expand-contract-and-destructive-ddl.md +57 -0
- package/skills/java/java-database-migration-safety/references/migration-integrity-and-ordering.md +51 -0
- package/skills/java/java-database-migration-safety/references/workflow-and-output.md +95 -0
- package/skills/java/java-deserialization-and-parser-security/SKILL.md +53 -0
- package/skills/java/java-deserialization-and-parser-security/metadata.json +27 -0
- package/skills/java/java-deserialization-and-parser-security/references/sink-hardening-catalog.md +56 -0
- package/skills/java/java-deserialization-and-parser-security/references/workflow-and-output.md +78 -0
- package/skills/java/java-framework-production-readiness/SKILL.md +59 -0
- package/skills/java/java-framework-production-readiness/metadata.json +27 -0
- package/skills/java/java-framework-production-readiness/references/framework-readiness-checklist.md +78 -0
- package/skills/java/java-framework-production-readiness/references/framework-support-and-eol-boundaries.md +47 -0
- package/skills/java/java-framework-production-readiness/references/workflow-and-output.md +108 -0
- package/skills/java/java-jdk-lifecycle-and-upgrade/SKILL.md +54 -0
- package/skills/java/java-jdk-lifecycle-and-upgrade/metadata.json +27 -0
- package/skills/java/java-jdk-lifecycle-and-upgrade/references/jdk-support-and-license-boundaries.md +61 -0
- package/skills/java/java-jdk-lifecycle-and-upgrade/references/lts-migration-and-language-features.md +159 -0
- package/skills/java/java-jdk-lifecycle-and-upgrade/references/workflow-and-output.md +101 -0
- package/skills/java/java-jpa-hibernate-performance/SKILL.md +53 -0
- package/skills/java/java-jpa-hibernate-performance/metadata.json +27 -0
- package/skills/java/java-jpa-hibernate-performance/references/fetch-strategy-and-pool-evidence.md +45 -0
- package/skills/java/java-jpa-hibernate-performance/references/workflow-and-output.md +94 -0
- package/skills/java/java-jvm-performance-and-gc/SKILL.md +59 -0
- package/skills/java/java-jvm-performance-and-gc/metadata.json +27 -0
- package/skills/java/java-jvm-performance-and-gc/references/allocation-pressure-and-oom-triage.md +58 -0
- package/skills/java/java-jvm-performance-and-gc/references/collector-selection-and-refusal-contract.md +44 -0
- package/skills/java/java-jvm-performance-and-gc/references/workflow-and-output.md +101 -0
- package/skills/java/java-kafka-reliability/SKILL.md +58 -0
- package/skills/java/java-kafka-reliability/metadata.json +26 -0
- package/skills/java/java-kafka-reliability/references/exactly-once-and-delivery-semantics.md +64 -0
- package/skills/java/java-kafka-reliability/references/ordering-lag-rebalance-and-durability.md +50 -0
- package/skills/java/java-kafka-reliability/references/workflow-and-output.md +107 -0
- package/skills/java/java-maestro/SKILL.md +111 -0
- package/skills/java/java-maestro/metadata.json +26 -0
- package/skills/java/java-resilience-pattern/SKILL.md +60 -0
- package/skills/java/java-resilience-pattern/metadata.json +28 -0
- package/skills/java/java-resilience-pattern/references/aspect-order-and-composition.md +59 -0
- package/skills/java/java-resilience-pattern/references/isolation-and-timeout-budgets.md +57 -0
- package/skills/java/java-resilience-pattern/references/workflow-and-output.md +103 -0
- package/skills/java/java-spring-security/SKILL.md +60 -0
- package/skills/java/java-spring-security/metadata.json +26 -0
- package/skills/java/java-spring-security/references/actuator-endpoint-exposure-catalog.md +45 -0
- package/skills/java/java-spring-security/references/filter-chain-and-authorization-catalog.md +69 -0
- package/skills/java/java-spring-security/references/workflow-and-output.md +79 -0
- package/skills/java/java-test-architecture/SKILL.md +64 -0
- package/skills/java/java-test-architecture/metadata.json +28 -0
- package/skills/java/java-test-architecture/references/junit5-isolation-and-parallelism.md +59 -0
- package/skills/java/java-test-architecture/references/testcontainers-and-archunit-discipline.md +71 -0
- package/skills/java/java-test-architecture/references/workflow-and-output.md +101 -0
- package/skills/java/java-transaction-and-consistency/SKILL.md +60 -0
- package/skills/java/java-transaction-and-consistency/metadata.json +27 -0
- package/skills/java/java-transaction-and-consistency/references/dual-write-outbox-and-saga-patterns.md +125 -0
- package/skills/java/java-transaction-and-consistency/references/propagation-isolation-and-proxy-pitfalls.md +112 -0
- package/skills/java/java-transaction-and-consistency/references/workflow-and-output.md +94 -0
- package/skills/php/composer-audit-supply-chain-review/SKILL.md +108 -0
- package/skills/php/composer-audit-supply-chain-review/metadata.json +20 -0
- package/skills/php/composer-audit-supply-chain-review/references/abandoned-and-advisory-governance.md +30 -0
- package/skills/php/composer-audit-supply-chain-review/references/composer-audit-policy.md +35 -0
- package/skills/php/composer-audit-supply-chain-review/references/lockfile-integrity.md +27 -0
- package/skills/php/php-maestro/SKILL.md +51 -0
- package/skills/php/php-maestro/metadata.json +20 -0
- package/skills/php/php-maestro/references/hard-gates-and-escalation.md +67 -0
- package/skills/php/php-maestro/references/routing-and-dispatch.md +91 -0
- package/skills/php/php-runtime-eol-opcache-fpm-review/SKILL.md +109 -0
- package/skills/php/php-runtime-eol-opcache-fpm-review/metadata.json +19 -0
- package/skills/php/php-runtime-eol-opcache-fpm-review/references/opcache-production-config.md +91 -0
- package/skills/php/php-runtime-eol-opcache-fpm-review/references/php-fpm-pool-tuning.md +87 -0
- package/skills/php/php-runtime-eol-opcache-fpm-review/references/php-version-lifecycle.md +102 -0
- package/skills/php/php-session-upload-deserialization-review/SKILL.md +111 -0
- package/skills/php/php-session-upload-deserialization-review/metadata.json +20 -0
- package/skills/php/php-session-upload-deserialization-review/references/file-upload-security.md +119 -0
- package/skills/php/php-session-upload-deserialization-review/references/session-security.md +126 -0
- package/skills/php/php-session-upload-deserialization-review/references/unserialize-object-injection.md +121 -0
- package/skills/php/wordpress-rest-block-security-review/SKILL.md +106 -0
- package/skills/php/wordpress-rest-block-security-review/metadata.json +20 -0
- package/skills/php/wordpress-rest-block-security-review/references/dynamic-block-output-escaping.md +42 -0
- package/skills/php/wordpress-rest-block-security-review/references/input-sanitize-output-escape.md +52 -0
- package/skills/php/wordpress-rest-block-security-review/references/rest-api-permission-callback.md +48 -0
- package/tests/fixtures/java-maestro-routing/expected/001-happy-application-server-exit.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/002-happy-concurrency-and-virtual-thread.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/003-happy-container-and-kubernetes-readiness.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/004-happy-database-migration-safety.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/005-happy-deserialization-and-parser-security.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/006-happy-framework-production-readiness.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/007-happy-jdk-lifecycle-and-upgrade.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/008-happy-jpa-hibernate-performance.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/009-happy-jvm-performance-and-gc.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/010-happy-kafka-reliability.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/011-happy-resilience-pattern.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/012-happy-spring-security.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/013-happy-test-architecture.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/014-happy-transaction-and-consistency.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/adv-ambiguous.json +4 -0
- package/tests/fixtures/java-maestro-routing/expected/adv-instruction-injection.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/adv-persona-replacement.json +6 -0
- package/tests/fixtures/java-maestro-routing/expected/adv-secrets-bait.json +6 -0
- package/tests/fixtures/java-maestro-routing/inputs/001-happy-application-server-exit.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/002-happy-concurrency-and-virtual-thread.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/003-happy-container-and-kubernetes-readiness.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/004-happy-database-migration-safety.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/005-happy-deserialization-and-parser-security.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/006-happy-framework-production-readiness.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/007-happy-jdk-lifecycle-and-upgrade.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/008-happy-jpa-hibernate-performance.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/009-happy-jvm-performance-and-gc.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/010-happy-kafka-reliability.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/011-happy-resilience-pattern.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/012-happy-spring-security.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/013-happy-test-architecture.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/014-happy-transaction-and-consistency.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/adv-ambiguous.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/adv-instruction-injection.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/adv-persona-replacement.json +7 -0
- package/tests/fixtures/java-maestro-routing/inputs/adv-secrets-bait.json +7 -0
- package/tests/fixtures/java-maestro-routing/taxonomy.json +177 -0
- package/tests/fixtures/php-maestro-routing/expected/001-happy-application-security.json +6 -0
- package/tests/fixtures/php-maestro-routing/expected/002-happy-composer-supply-chain.json +6 -0
- package/tests/fixtures/php-maestro-routing/expected/003-happy-runtime-upgrade-readiness.json +6 -0
- package/tests/fixtures/php-maestro-routing/expected/004-happy-wordpress-security.json +6 -0
- package/tests/fixtures/php-maestro-routing/expected/005-happy-unserialize-session.json +6 -0
- package/tests/fixtures/php-maestro-routing/expected/006-happy-fpm-opcache.json +6 -0
- package/tests/fixtures/php-maestro-routing/expected/007-happy-composer-audit.json +6 -0
- package/tests/fixtures/php-maestro-routing/expected/008-happy-wp-permission-callback.json +6 -0
- package/tests/fixtures/php-maestro-routing/expected/adv-ambiguous.json +4 -0
- package/tests/fixtures/php-maestro-routing/expected/adv-instruction-injection.json +6 -0
- package/tests/fixtures/php-maestro-routing/expected/adv-liveguard-db-migration-prod.json +4 -0
- package/tests/fixtures/php-maestro-routing/expected/adv-liveguard-deploy-prod.json +4 -0
- package/tests/fixtures/php-maestro-routing/expected/adv-persona-replacement.json +6 -0
- package/tests/fixtures/php-maestro-routing/expected/adv-secrets-bait.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/001-happy-application-security.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/002-happy-composer-supply-chain.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/003-happy-runtime-upgrade-readiness.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/004-happy-wordpress-security.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/005-happy-unserialize-session.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/006-happy-fpm-opcache.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/007-happy-composer-audit.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/008-happy-wp-permission-callback.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/adv-ambiguous.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/adv-instruction-injection.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/adv-liveguard-db-migration-prod.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/adv-liveguard-deploy-prod.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/adv-persona-replacement.json +7 -0
- package/tests/fixtures/php-maestro-routing/inputs/adv-secrets-bait.json +7 -0
- package/tests/fixtures/php-maestro-routing/taxonomy.json +69 -0
- package/tests/validate-catalog.py +2 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# PHP version lifecycle
|
|
2
|
+
|
|
3
|
+
## Why this matters
|
|
4
|
+
|
|
5
|
+
A PHP branch that has left php.net's supported window stops receiving fixes of
|
|
6
|
+
any kind once it reaches end of life (EOL) — including for actively exploited
|
|
7
|
+
vulnerabilities — while a branch in its security-only window still receives
|
|
8
|
+
critical security fixes but no bug fixes, and is itself counting down to its
|
|
9
|
+
own EOL. A service can look fully healthy at the application-code level (green
|
|
10
|
+
tests, current dependencies) while the runtime underneath it has already
|
|
11
|
+
crossed one of these boundaries. This file is the sole source the skill uses
|
|
12
|
+
for those dates; every version-lifecycle claim in a review must resolve to a
|
|
13
|
+
row below, and to no other memory or estimate.
|
|
14
|
+
|
|
15
|
+
## NORMATIVE: php.net's support policy
|
|
16
|
+
|
|
17
|
+
Per php.net's Supported Versions page (`documentation-based`):
|
|
18
|
+
|
|
19
|
+
- Each release branch of PHP is fully supported for **two years** from its
|
|
20
|
+
initial stable release. During this period, reported bugs and security
|
|
21
|
+
issues are fixed and released in regular point releases.
|
|
22
|
+
- After that two-year active-support period, each branch is then supported
|
|
23
|
+
for **two additional years** for critical security issues only. Releases
|
|
24
|
+
during this window are made on an as-needed basis — there may be multiple
|
|
25
|
+
point releases, or none, depending on the number of reports.
|
|
26
|
+
- After the combined four-year window (two years active plus two years
|
|
27
|
+
security-only), a branch is **end of life (EOL)**: no further fixes of any
|
|
28
|
+
kind are published for it, including for actively exploited
|
|
29
|
+
vulnerabilities.
|
|
30
|
+
|
|
31
|
+
## NORMATIVE: current per-branch dates
|
|
32
|
+
|
|
33
|
+
Per php.net's Supported Versions page, the currently listed branches and
|
|
34
|
+
their published dates are:
|
|
35
|
+
|
|
36
|
+
| Branch | Active support until | Security support until (EOL) |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| PHP 8.2 | 31 Dec 2024 | 31 Dec 2026 |
|
|
39
|
+
| PHP 8.3 | 31 Dec 2025 | 31 Dec 2027 |
|
|
40
|
+
| PHP 8.4 | 31 Dec 2026 | 31 Dec 2028 |
|
|
41
|
+
| PHP 8.5 | 31 Dec 2027 | 31 Dec 2029 |
|
|
42
|
+
|
|
43
|
+
Reading this table for a review:
|
|
44
|
+
|
|
45
|
+
- A branch is in **active support** if the current review's target/committed
|
|
46
|
+
version date is before its "Active support until" date.
|
|
47
|
+
- A branch is in **security-only support** if that date is on or after
|
|
48
|
+
"Active support until" but before "Security support until."
|
|
49
|
+
- A branch is **EOL** once that date reaches or passes "Security support
|
|
50
|
+
until" — no fixes of any kind are published past that point.
|
|
51
|
+
|
|
52
|
+
Any PHP version not listed in php.net's current supported-versions table
|
|
53
|
+
(either older than the branches php.net still lists, or a malformed/future
|
|
54
|
+
version string) has no dates in this file — say the evidence is missing
|
|
55
|
+
rather than inferring a status.
|
|
56
|
+
|
|
57
|
+
## Reviewer evidence criteria
|
|
58
|
+
|
|
59
|
+
- Resolve the exact PHP version from the strongest available evidence:
|
|
60
|
+
a running-version banner or `phpversion()`/`php -v` output outranks a
|
|
61
|
+
Dockerfile/base-image tag, which outranks a loose Composer `require.php`
|
|
62
|
+
constraint (e.g. `^8.2` does not tell you which point release is actually
|
|
63
|
+
deployed, only the minimum branch). State which evidence tier the version
|
|
64
|
+
claim rests on.
|
|
65
|
+
- Match the resolved branch against the table above exactly; do not round a
|
|
66
|
+
point release to a different branch or assume a branch's status from a
|
|
67
|
+
prior review.
|
|
68
|
+
- Classify the branch precisely as active support, security-only (cite the
|
|
69
|
+
exact security-support-until date), or EOL (cite the exact date it was
|
|
70
|
+
reached) — never collapse these into an undifferentiated "outdated" label.
|
|
71
|
+
- Determine the branch's **current phase** by comparing this file's published
|
|
72
|
+
cutoff dates against the review date — the current date, or an explicitly
|
|
73
|
+
supplied review/support-horizon date when one is given. This file's
|
|
74
|
+
per-branch dates are the fixed ground truth (sourced from php.net, never
|
|
75
|
+
invented, rounded, or extrapolated); only the comparison against the review
|
|
76
|
+
date is a review-time judgment, so a branch correctly transitions from
|
|
77
|
+
active support to security-only to EOL as the review date passes each
|
|
78
|
+
published cutoff.
|
|
79
|
+
- For a security-only branch, compare its "Security support until" date
|
|
80
|
+
against both the review date and the review's stated release/support
|
|
81
|
+
horizon. If EOL has already been reached, or that date falls within the
|
|
82
|
+
horizon with no tracked upgrade plan, this is a blocking finding per the
|
|
83
|
+
skill's decision gates, not merely advisory.
|
|
84
|
+
- For an EOL branch, the finding is blocking unconditionally — there is no
|
|
85
|
+
"well-maintained otherwise" exception, since EOL means no fixes of any kind
|
|
86
|
+
are published, including for actively exploited vulnerabilities.
|
|
87
|
+
|
|
88
|
+
## NORMATIVE vs. RECOMMENDATION
|
|
89
|
+
|
|
90
|
+
The support-policy structure and the per-branch dates above are NORMATIVE —
|
|
91
|
+
sourced directly from php.net and not to be altered, rounded, or
|
|
92
|
+
extrapolated. The recommended target version for an upgrade (e.g. "move to
|
|
93
|
+
the newest branch still in active support") is a RECOMMENDATION: name a
|
|
94
|
+
target that is currently in active support per the table above, but leave the
|
|
95
|
+
final choice, timeline, and any compatibility work to the owning engineering
|
|
96
|
+
team.
|
|
97
|
+
|
|
98
|
+
## Sources
|
|
99
|
+
|
|
100
|
+
- [PHP: Supported Versions](https://www.php.net/supported-versions.php) — supports the two-year active-support / two-year security-only / EOL support-policy structure and the per-branch dates for PHP 8.2 through 8.5 above.
|
|
101
|
+
|
|
102
|
+
Last verified: 2026-07-16.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: php-session-upload-deserialization-review
|
|
3
|
+
description: Use this skill to statically review PHP code for object-injection risk from unserialize() on untrusted input, session fixation/hijacking from missing session_regenerate_id() or weak session cookie hardening, and unsafe file-upload handling that trusts the client or stores/executes uploads inside the webroot. Use when reviewing a PHP application for deserialization, authentication-session, or upload-handling security issues. Static review only; it never executes payloads, uploads, or requests against any system, and every unserialize()/session/upload claim is grounded in the current php.net manual rather than memory.
|
|
4
|
+
allowed-tools: Read Grep Glob
|
|
5
|
+
metadata:
|
|
6
|
+
author: "github: Raishin"
|
|
7
|
+
version: "0.1.0"
|
|
8
|
+
updated: "2026-07-16"
|
|
9
|
+
category: security
|
|
10
|
+
lifecycle: experimental
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# PHP Session, Upload, and Deserialization Review
|
|
14
|
+
|
|
15
|
+
## Purpose
|
|
16
|
+
|
|
17
|
+
Review PHP source for the three failure modes where the language's own deserialization, session, and file-upload primitives are used in a way php.net's own manual explicitly warns against: `unserialize()` called on untrusted input (object injection, potentially remote code execution), a session that is not regenerated after a privilege change or that ships without cookie hardening (fixation/hijacking), and an upload handler that trusts the client or stores/executes accepted files inside the webroot.
|
|
18
|
+
|
|
19
|
+
## When to use
|
|
20
|
+
|
|
21
|
+
Use this skill when the user asks to:
|
|
22
|
+
|
|
23
|
+
- review any code path that calls `unserialize()`, or a library/cache/session backend that transparently unserializes stored data, for object-injection risk;
|
|
24
|
+
- review whether a login, role-elevation, or password-reset path correctly regenerates the session id and whether session cookie hardening (`use_strict_mode`, `httponly`, `secure`, `samesite`) is configured;
|
|
25
|
+
- review a file-upload handler for client-trust, storage-location, or size/type/count-limit gaps.
|
|
26
|
+
|
|
27
|
+
## When not to use
|
|
28
|
+
|
|
29
|
+
Do not use this skill for:
|
|
30
|
+
|
|
31
|
+
- designing or approving a backend authorization/permission model — this skill only checks whether a privilege change triggers session regeneration, not whether the privilege model itself is correct; hand that off to the owning backend/platform specialist.
|
|
32
|
+
- executing, crafting, or sending any deserialization payload, session-fixation request, or file upload against any live, sandbox, or staging system. This skill is static review only.
|
|
33
|
+
- issuing a compliance or audit attestation from an OWASP category mapping; the mapping is a classification aid, never a determination.
|
|
34
|
+
|
|
35
|
+
## Preconditions
|
|
36
|
+
|
|
37
|
+
- The code paths that call `unserialize()`, plus the source of the data passed to each call (request body/query/cookie, cache backend, queue message, database column).
|
|
38
|
+
- The authentication/session-management code, specifically where `session_start()`, `session_regenerate_id()`, and `$_SESSION` writes occur relative to a login, role change, or password reset.
|
|
39
|
+
- The active `session.*` INI settings in scope (`session.use_strict_mode`, `session.cookie_httponly`, `session.cookie_secure`, `session.cookie_samesite`) from `php.ini`, `.htaccess`, or runtime `ini_set()` calls.
|
|
40
|
+
- The upload-handling code: how `$_FILES` is validated, where accepted files are stored, and the `upload_max_filesize`/`post_max_size`/`max_file_uploads` configuration in effect.
|
|
41
|
+
- The PHP version in scope (`session.cookie_samesite` requires PHP 7.3+; destructor-on-fatal-error behavior changed at PHP 5.3.10).
|
|
42
|
+
|
|
43
|
+
## Lean operating rules
|
|
44
|
+
|
|
45
|
+
- Flag any `unserialize()` call on untrusted input regardless of `allowed_classes` — the manual's caution applies unconditionally, and `allowed_classes` narrows instantiable classes without making the call safe.
|
|
46
|
+
- Name the reachable magic-method surface (`__wakeup()`, `__unserialize()`, `__destruct()`) for any class an untrusted `unserialize()` call could instantiate; PHP invokes these automatically on the reconstructed object or during the shutdown sequence.
|
|
47
|
+
- Recommend `json_decode()`/`json_encode()` as the default remediation for untrusted data interchange unless serialized PHP objects are confirmed necessary.
|
|
48
|
+
- Require `session_regenerate_id(true)` before the authenticated flag is written to `$_SESSION` on every login/elevation/reset path; a regeneration call placed after that write is a finding, not a pass.
|
|
49
|
+
- Check `session.use_strict_mode`, `session.cookie_httponly`, `session.cookie_secure`, and `session.cookie_samesite` individually and explicitly; never infer hardening from defaults, since `use_strict_mode` is disabled by default.
|
|
50
|
+
- Require upload handlers to validate the file's actual content server-side (never the client-supplied `$_FILES[...]['type']` or filename alone), store accepted files outside any web-servable path, and enforce `upload_max_filesize`, `post_max_size`, and `max_file_uploads`.
|
|
51
|
+
- Never request, echo, store, or reproduce a secret, credential, session id, token, or PII found in reviewed code; redact-and-flag any such string.
|
|
52
|
+
- Label every claim `repo evidence` (seen in the reviewed code) or `documentation-based` (current php.net manual); never assert a documented API behavior from memory.
|
|
53
|
+
|
|
54
|
+
## Context7 documentation protocol
|
|
55
|
+
|
|
56
|
+
This skill's `allowed-tools` is limited to `Read`, `Grep`, and `Glob` — it does not include a live documentation-lookup tool, so grounding is done against the bundled, php.net-sourced reference files rather than a runtime Context7 call. `unserialize()`, the `session.*` INI directives, and the upload-handling behaviors reviewed here are core-language documentation, not a third-party library whose API shifts release to release, so the bundled references (each fetched directly from php.net, with its own Sources section and verification date) are the grounding source of record. If a review surfaces a claim about PHP behavior not covered by the bundled references — a different function, a different INI directive, a different PHP version's behavior — do not assert it from memory; say the claim is unverified against a specific php.net page and escalate for direct verification rather than guessing.
|
|
57
|
+
|
|
58
|
+
## Workflow
|
|
59
|
+
|
|
60
|
+
1. Enumerate every `unserialize()` call site in scope and trace the data source of its argument; classify each as untrusted-input-reachable or not.
|
|
61
|
+
2. For each untrusted-input-reachable `unserialize()` call, identify classes it could instantiate and check for `__wakeup()`, `__unserialize()`, and `__destruct()` magic methods that would fire automatically — see [Unserialize object injection](references/unserialize-object-injection.md).
|
|
62
|
+
3. For each authentication/privilege-elevation path, confirm `session_regenerate_id(true)` is called before `$_SESSION` carries the authenticated flag, and check the four session-hardening directives — see [Session security](references/session-security.md).
|
|
63
|
+
4. For each upload handler, confirm server-side content validation, non-webroot storage, and enforced size/type/count limits — see [File upload security](references/file-upload-security.md).
|
|
64
|
+
5. Emit findings with evidence tiers, exploit/failure narratives, remediation, verification steps, and OWASP category mappings; hand off any authorization-model or infrastructure-scoped issue to the owning specialist.
|
|
65
|
+
|
|
66
|
+
## Decision gates
|
|
67
|
+
|
|
68
|
+
- Block only on a demonstrated untrusted-input-reachable `unserialize()` call, a missing/misordered `session_regenerate_id()` call, a missing `session.use_strict_mode`, or an upload handler that trusts the client, stores inside the webroot, or lacks enforced limits.
|
|
69
|
+
- Every `unserialize()`, session-directive, or upload-limit claim cites the current php.net manual (`documentation-based`) or the reviewed code (`repo evidence`) — never memory.
|
|
70
|
+
- Every OWASP mapping names the specific edition and category cited and is labeled a classification aid, never a compliance determination.
|
|
71
|
+
- Every authorization-model-design or infrastructure-scoped finding is handed off, not adjudicated here.
|
|
72
|
+
|
|
73
|
+
## Evidence classification
|
|
74
|
+
|
|
75
|
+
Label each finding `repo evidence` (seen directly in the reviewed code or configuration) or `documentation-based` (the current php.net manual). This skill does not use `context7-grounded` (no Context7 tool in scope) and does not use `inference` for a documented API behavior — an undocumented or unverifiable behavior claim must be flagged as unverified rather than guessed.
|
|
76
|
+
|
|
77
|
+
## Security and privacy constraints
|
|
78
|
+
|
|
79
|
+
Static review only. Never request, transmit, store, or reproduce a secret, credential, session id, token, or PII found in reviewed code or configuration; treat any such string as a redact-and-flag finding. Never execute a deserialization payload, replay or forge a session id, upload a file, or send any request to a live, sandbox, or staging system. OWASP category mappings are classification aids, never compliance attestations.
|
|
80
|
+
|
|
81
|
+
## Escalation conditions
|
|
82
|
+
|
|
83
|
+
Escalate to incident response on any evidence the failure is already live: an object-injection payload observed in logs, a reachable uploaded web shell, or an observed session id reused across a privilege boundary. Escalate backend authorization-model design and infrastructure-scoped findings (webroot layout, TLS termination) to their owning specialist rather than adjudicating them here.
|
|
84
|
+
|
|
85
|
+
## References
|
|
86
|
+
|
|
87
|
+
Load these only when needed:
|
|
88
|
+
|
|
89
|
+
- [Unserialize object injection](references/unserialize-object-injection.md) — why `unserialize()` on untrusted input is unsafe regardless of `allowed_classes`, the magic-method attack surface, and the `json_decode()` remediation.
|
|
90
|
+
- [Session security](references/session-security.md) — `session_regenerate_id()` ordering around privilege changes and the four session cookie-hardening directives.
|
|
91
|
+
- [File upload security](references/file-upload-security.md) — client-trust, storage-location, and size/type/count-limit review criteria for upload handlers.
|
|
92
|
+
|
|
93
|
+
Each reference file carries its own Sources section citing the exact php.net (or OWASP) page backing its claims — there is no separate primary-source ledger file in this skill.
|
|
94
|
+
|
|
95
|
+
## Response minimum
|
|
96
|
+
|
|
97
|
+
Return, at minimum:
|
|
98
|
+
|
|
99
|
+
- the call site/path in scope and, per finding, the failure class (`object-injection` / `session-fixation-hijacking` / `unsafe-upload`) and evidence tier;
|
|
100
|
+
- the exploit or failure narrative (how the reachable input reaches a wrong outcome);
|
|
101
|
+
- concrete remediation and an exact verification step;
|
|
102
|
+
- the OWASP category mapping, labeled as a classification aid;
|
|
103
|
+
- any authorization-model or infrastructure-scoped handoffs and incident-response escalation.
|
|
104
|
+
|
|
105
|
+
## Anti-goals
|
|
106
|
+
|
|
107
|
+
- Do not treat `allowed_classes` as a mitigation for `unserialize()` on untrusted input; the manual's caution is unconditional.
|
|
108
|
+
- Do not design or approve a backend authorization/permission model; hand it off.
|
|
109
|
+
- Do not execute any payload, upload, or request against any live, sandbox, or staging system.
|
|
110
|
+
- Do not assert `unserialize()`, session-directive, or upload-limit behavior from memory; ground every such claim in the current php.net manual.
|
|
111
|
+
- Do not echo, store, or reproduce any secret, session id, token, or PII found during review.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "php-session-upload-deserialization-review",
|
|
3
|
+
"name": "PHP Session, Upload & Deserialization Security Review",
|
|
4
|
+
"type": "skill",
|
|
5
|
+
"provider": "php",
|
|
6
|
+
"harnesses": ["claude-code", "cursor", "codex", "gemini", "kiro", "other"],
|
|
7
|
+
"summary": "Skill for reviewing PHP application-security seams: user-reachable unserialize() object injection (allowed_classes is insufficient), session fixation/hijacking hardening (session_regenerate_id, use_strict_mode, cookie flags), and unsafe file-upload handling, each mapped to an OWASP category and the php.net-documented fix.",
|
|
8
|
+
"source_type": "original",
|
|
9
|
+
"official_docs": [
|
|
10
|
+
"https://www.php.net/manual/en/function.unserialize.php",
|
|
11
|
+
"https://www.php.net/manual/en/session.security.php",
|
|
12
|
+
"https://www.php.net/manual/en/features.file-upload.common-pitfalls.php",
|
|
13
|
+
"https://owasp.org/www-project-top-ten/"
|
|
14
|
+
],
|
|
15
|
+
"security_notes": "Static-review-only skill: Read/Grep/Glob, no execution and no network. Never runs deserialization payloads, uploads, or exploits against any live or staging system. Any credential- or PII-shaped string is a redact-and-flag finding, never echoed. Every unserialize()/session/upload claim is grounded in current php.net documentation, not memory.",
|
|
16
|
+
"last_verified": "2026-07-16",
|
|
17
|
+
"path": "skills/php/php-session-upload-deserialization-review",
|
|
18
|
+
"author": "github: Raishin",
|
|
19
|
+
"version": "0.1.0"
|
|
20
|
+
}
|
package/skills/php/php-session-upload-deserialization-review/references/file-upload-security.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# File upload security
|
|
2
|
+
|
|
3
|
+
## Why this matters
|
|
4
|
+
|
|
5
|
+
An upload handler is the one place in most PHP applications where a client
|
|
6
|
+
supplies content the server will store, and often later serve, on its own
|
|
7
|
+
filesystem. Every trust decision the manual warns against — believing the
|
|
8
|
+
client's stated MIME type, believing the client's filename, skipping the
|
|
9
|
+
configured size/count ceilings, or placing accepted content somewhere the
|
|
10
|
+
web server will execute it — turns a routine upload feature into a path for
|
|
11
|
+
an attacker to plant and run a web shell, exhaust server resources, or read
|
|
12
|
+
files the application never meant to expose.
|
|
13
|
+
|
|
14
|
+
## NORMATIVE: configuration ceilings gate every upload
|
|
15
|
+
|
|
16
|
+
Per the php.net manual's common-pitfalls guidance for file uploads:
|
|
17
|
+
|
|
18
|
+
- **`upload_max_filesize`** caps the size PHP will accept per file: "The
|
|
19
|
+
`MAX_FILE_SIZE` item cannot specify a file size greater than the file size
|
|
20
|
+
that has been set in the `upload_max_filesize` in the php.ini file. The
|
|
21
|
+
default is 2 megabytes." A form-field `MAX_FILE_SIZE` hint is a
|
|
22
|
+
client-side convenience only; the server-enforced ceiling is
|
|
23
|
+
`upload_max_filesize`.
|
|
24
|
+
- **`post_max_size`** must accommodate the request as a whole: "If
|
|
25
|
+
`post_max_size` is set too small, large files cannot be uploaded. Make
|
|
26
|
+
sure you set `post_max_size` large enough." A `post_max_size` smaller than
|
|
27
|
+
`upload_max_filesize` silently caps effective upload size below what
|
|
28
|
+
`upload_max_filesize` alone suggests.
|
|
29
|
+
- **`max_file_uploads`** bounds how many files one request can carry: "The
|
|
30
|
+
`max_file_uploads` configuration setting controls the maximum number of
|
|
31
|
+
files that can [be] uploaded in one request. If more files are uploaded
|
|
32
|
+
than the limit, then `$_FILES` will stop processing files once the limit
|
|
33
|
+
is reached" — silently, not with an error the handler is guaranteed to
|
|
34
|
+
check for.
|
|
35
|
+
- **`memory_limit`**, **`max_execution_time`**, and **`max_input_time`** must
|
|
36
|
+
also be sized for uploads: the manual specifically notes `max_input_time`
|
|
37
|
+
"sets the maximum time, in seconds, the script is allowed to receive
|
|
38
|
+
input; this includes file uploads. For large or multiple files, or users
|
|
39
|
+
on slower connections, the default of `60` seconds may be exceeded,"
|
|
40
|
+
causing an otherwise-valid upload to fail partway through.
|
|
41
|
+
|
|
42
|
+
A review must confirm these are set deliberately (not left at silent
|
|
43
|
+
defaults that either reject legitimate uploads or, in the case of
|
|
44
|
+
`max_file_uploads`, silently truncate a batch without the handler noticing).
|
|
45
|
+
|
|
46
|
+
## NORMATIVE: do not trust which file you operate on
|
|
47
|
+
|
|
48
|
+
The manual's common-pitfalls page states plainly: "Not validating which file
|
|
49
|
+
you operate on may mean that users can access sensitive information in
|
|
50
|
+
other directories." This is the manual's own framing of path-traversal and
|
|
51
|
+
client-trust risk in upload handling — a filename or path is untrusted input
|
|
52
|
+
like any other and must be validated, not built into a filesystem operation
|
|
53
|
+
directly. The manual separately cautions that "due to the large amount of
|
|
54
|
+
directory listing styles we cannot guarantee that files with exotic names
|
|
55
|
+
(like containing spaces) are handled properly," reinforcing that the
|
|
56
|
+
client-supplied filename cannot be relied on to behave predictably and
|
|
57
|
+
should not be used to construct a storage path or to make a security
|
|
58
|
+
decision (such as inferring file type from its extension).
|
|
59
|
+
|
|
60
|
+
## RECOMMENDATION: validate content, not client claims; store outside the webroot
|
|
61
|
+
|
|
62
|
+
The manual's guidance above establishes the principle — validate the file
|
|
63
|
+
you actually operate on — but does not itself specify a validation
|
|
64
|
+
algorithm or a storage location; the following are this skill's operating
|
|
65
|
+
recommendations applying that principle, to be checked as reviewer evidence
|
|
66
|
+
criteria below rather than cited as separate manual quotations:
|
|
67
|
+
|
|
68
|
+
- Treat `$_FILES[...]['type']` (client-reported MIME type) and
|
|
69
|
+
`$_FILES[...]['name']` (client-reported filename) as untrusted metadata
|
|
70
|
+
only. A security decision — what kind of file this is, whether it is
|
|
71
|
+
acceptable — must be made from the file's actual content on the server,
|
|
72
|
+
not from either client-supplied field.
|
|
73
|
+
- Store accepted uploads outside any path the web server will serve
|
|
74
|
+
directly, and generate the stored filename server-side rather than
|
|
75
|
+
reusing the client-supplied name verbatim, closing both the
|
|
76
|
+
path-traversal risk above and the risk of an executable extension being
|
|
77
|
+
preserved into a servable location.
|
|
78
|
+
- Never `include()`, `require()`, or otherwise execute an uploaded file as
|
|
79
|
+
PHP code, and never configure the storage directory to be
|
|
80
|
+
script-executable by the web server.
|
|
81
|
+
|
|
82
|
+
## Reviewer evidence criteria
|
|
83
|
+
|
|
84
|
+
For each upload handler in scope:
|
|
85
|
+
|
|
86
|
+
- Confirm `upload_max_filesize`, `post_max_size` (sized larger than
|
|
87
|
+
`upload_max_filesize`), and `max_file_uploads` are set to deliberate,
|
|
88
|
+
documented values rather than left at framework/PHP defaults without
|
|
89
|
+
review, and confirm the handler does not assume a client-side
|
|
90
|
+
`MAX_FILE_SIZE` hint is enforced.
|
|
91
|
+
- Confirm the handler checks the actual number of files processed against
|
|
92
|
+
what the client claims to have sent, given that `$_FILES` silently stops
|
|
93
|
+
populating once `max_file_uploads` is reached.
|
|
94
|
+
- Confirm the handler validates the file's real type/content server-side,
|
|
95
|
+
not `$_FILES[...]['type']` or the client filename's extension alone.
|
|
96
|
+
- Confirm accepted files are stored outside any web-servable path, with a
|
|
97
|
+
server-generated filename, not the client-supplied one used verbatim in
|
|
98
|
+
a filesystem path.
|
|
99
|
+
- Confirm no code path `include()`s, `require()`s, or otherwise executes an
|
|
100
|
+
uploaded file, and that the storage location is not configured as
|
|
101
|
+
script-executable.
|
|
102
|
+
- Treat trusting client-supplied MIME type/filename for a security decision,
|
|
103
|
+
storing inside the webroot, or having no enforced size/type/count limit as
|
|
104
|
+
a blocking finding.
|
|
105
|
+
|
|
106
|
+
## Applicable versions
|
|
107
|
+
|
|
108
|
+
The `upload_max_filesize` default (2 megabytes) and the `max_file_uploads`
|
|
109
|
+
silent-truncation behavior described above are current php.net manual
|
|
110
|
+
guidance as of this review; re-verify against the live manual page before
|
|
111
|
+
citing an exact default value, since PHP distribution defaults (and
|
|
112
|
+
distro-specific `php.ini` overrides) can differ from the documented
|
|
113
|
+
upstream default.
|
|
114
|
+
|
|
115
|
+
## Sources
|
|
116
|
+
|
|
117
|
+
- [PHP Manual — Common Pitfalls (file uploads)](https://www.php.net/manual/en/features.file-upload.common-pitfalls.php) — supports the `upload_max_filesize` default and `MAX_FILE_SIZE` client-hint framing, the `post_max_size` sizing guidance, the `max_file_uploads` silent-stop behavior, the `max_input_time` upload-duration caution, and the "not validating which file you operate on" and "exotic names" client-trust cautions.
|
|
118
|
+
|
|
119
|
+
Last verified: 2026-07-16.
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Session security
|
|
2
|
+
|
|
3
|
+
## Why this matters
|
|
4
|
+
|
|
5
|
+
A session id is a bearer credential: whoever presents it is treated as the
|
|
6
|
+
user it belongs to. Two distinct failures let an attacker end up holding a
|
|
7
|
+
victim's session id: fixation, where the attacker sets the session id before
|
|
8
|
+
the victim authenticates and it is never replaced, and hijacking, where the
|
|
9
|
+
attacker steals an already-authenticated session id after the fact (via
|
|
10
|
+
script injection, packet sniffing, or physical access). php.net's own
|
|
11
|
+
session-security guidance treats both as core, not edge-case, concerns, and
|
|
12
|
+
documents specific configuration and code-ordering requirements to close
|
|
13
|
+
each path.
|
|
14
|
+
|
|
15
|
+
## NORMATIVE: regenerate the session id on privilege change
|
|
16
|
+
|
|
17
|
+
Per the php.net manual's session-management-basics guidance:
|
|
18
|
+
|
|
19
|
+
- "Session IDs **must** be regenerated when user privileges are elevated,
|
|
20
|
+
such as after authenticating. `session_regenerate_id()` must be called
|
|
21
|
+
prior to setting the authentication information to `$_SESSION`."
|
|
22
|
+
`session_regenerate_id()` saves the current session data automatically, so
|
|
23
|
+
the call itself does not lose session state — but it must come **before**
|
|
24
|
+
the authenticated flag is written, so that only the new session id carries
|
|
25
|
+
it.
|
|
26
|
+
- More generally: "Session ID regeneration reduces the risk of stolen
|
|
27
|
+
session IDs, thus `session_regenerate_id()` must be called periodically.
|
|
28
|
+
E.g. Regenerate the session ID every 15 minutes for security sensitive
|
|
29
|
+
content."
|
|
30
|
+
- `session_regenerate_id()` does **not** delete the outdated session's data
|
|
31
|
+
by default. The manual is explicit: "`session_regenerate_id()` does not
|
|
32
|
+
delete outdated sessions by default. Obsolete authenticated sessions may
|
|
33
|
+
be present for use. Developers must prevent outdated sessions to be
|
|
34
|
+
consumed by anyone." A regeneration call without also invalidating the
|
|
35
|
+
prior session's stored data leaves a still-valid, still-authenticated old
|
|
36
|
+
session id usable by anyone who captured it before regeneration.
|
|
37
|
+
|
|
38
|
+
## NORMATIVE: `session.use_strict_mode` is mandatory and off by default
|
|
39
|
+
|
|
40
|
+
Per the manual: "enabling `session.use_strict_mode` is mandatory for secure
|
|
41
|
+
sessions. It is disabled by default. This prevents the session module [from
|
|
42
|
+
using] an uninitialized session ID. Put differently, the session module only
|
|
43
|
+
accepts valid session IDs generated by the session module. It rejects any
|
|
44
|
+
session ID supplied by users." With strict mode enabled, "an uninitialized
|
|
45
|
+
session ID is rejected and a new one is created. This prevents an attack that
|
|
46
|
+
forces users to use a known session ID" — the core session-fixation vector,
|
|
47
|
+
where an attacker "may paste links or send emails that contain the session
|
|
48
|
+
ID" and hope the victim's session simply adopts it.
|
|
49
|
+
|
|
50
|
+
Because this directive is **disabled by default**, a review must check for
|
|
51
|
+
an explicit `session.use_strict_mode=1` (or equivalent `ini_set()` call) —
|
|
52
|
+
absence of an error or warning is not evidence it is on.
|
|
53
|
+
|
|
54
|
+
## NORMATIVE: cookie-hardening directives
|
|
55
|
+
|
|
56
|
+
Per the php.net manual's session INI-settings guidance, four directives
|
|
57
|
+
harden the session cookie itself:
|
|
58
|
+
|
|
59
|
+
- **`session.cookie_httponly`** — "Refuses access to the session cookie from
|
|
60
|
+
JavaScript. This setting prevents cookies snatched by a JavaScript
|
|
61
|
+
injection." The manual states: "Almost all applications must use the
|
|
62
|
+
httponly attribute for the session ID cookie."
|
|
63
|
+
- **`session.cookie_secure`** — "Allow access to the session ID cookie only
|
|
64
|
+
when the protocol is HTTPS. If a website is only accessible via HTTPS, it
|
|
65
|
+
should enable this setting." (The manual separately notes HSTS should be
|
|
66
|
+
considered for HTTPS-only sites.)
|
|
67
|
+
- **`session.cookie_samesite`** — "As of PHP 7.3 the `SameSite` attribute can
|
|
68
|
+
be set for the session ID cookie. This attribute is a way to mitigate CSRF
|
|
69
|
+
(Cross Site Request Forgery) attacks." `Lax` allows the cookie on a
|
|
70
|
+
cross-site GET navigation; `Strict` does not send it cross-site at all —
|
|
71
|
+
the manual frames the choice as that accessibility trade-off, not a
|
|
72
|
+
recommendation of one value for every application.
|
|
73
|
+
- Session hijacking generally (not fixation) is mitigated, per the manual,
|
|
74
|
+
by transport: "There are several ways to leak an existing session ID to
|
|
75
|
+
third parties. E.g. JavaScript injections, session IDs in URLs, packet
|
|
76
|
+
sniffing, physical access to the device, etc... The solution is to
|
|
77
|
+
implement SSL/TLS on the server and make it mandatory for users" —
|
|
78
|
+
`session.cookie_secure` is the configuration lever that enforces this for
|
|
79
|
+
the session cookie specifically.
|
|
80
|
+
|
|
81
|
+
## Reviewer evidence criteria
|
|
82
|
+
|
|
83
|
+
For every authentication, privilege-elevation, or password-reset path:
|
|
84
|
+
|
|
85
|
+
- Confirm `session_regenerate_id(true)` is called, and confirm it is called
|
|
86
|
+
**before** the code writes the authenticated/elevated-privilege flag into
|
|
87
|
+
`$_SESSION`. A call present anywhere in the function is not sufficient —
|
|
88
|
+
check the ordering.
|
|
89
|
+
- Confirm the prior session's data is invalidated or is not relied upon as
|
|
90
|
+
still-authenticated after regeneration; a regeneration call with the old
|
|
91
|
+
session id left independently valid and authenticated is a finding.
|
|
92
|
+
|
|
93
|
+
For the effective session configuration in scope (`php.ini`, `.htaccess`,
|
|
94
|
+
`ini_set()` calls, or a framework's session configuration layer):
|
|
95
|
+
|
|
96
|
+
- Confirm `session.use_strict_mode` is explicitly enabled; do not treat its
|
|
97
|
+
absence from configuration as acceptable, since it is disabled by default.
|
|
98
|
+
- Confirm `session.cookie_httponly` is enabled.
|
|
99
|
+
- Confirm `session.cookie_secure` is enabled for any application served over
|
|
100
|
+
HTTPS (and flag its absence as a finding for an HTTPS-only application).
|
|
101
|
+
- Confirm `session.cookie_samesite` is set to `Lax` or `Strict` (requires
|
|
102
|
+
PHP 7.3+); flag an unset value, and flag PHP < 7.3 as unable to set this
|
|
103
|
+
directive at all (a version-upgrade finding, not a configuration finding).
|
|
104
|
+
|
|
105
|
+
Treat a missing `session_regenerate_id()` call (or one ordered after the
|
|
106
|
+
authenticated flag is set) and a missing/disabled `session.use_strict_mode`
|
|
107
|
+
as blocking findings. Treat missing `cookie_httponly`, `cookie_secure`, or
|
|
108
|
+
`cookie_samesite` as findings that escalate to blocking when combined with
|
|
109
|
+
any independently confirmed session-id-leak or fixation path.
|
|
110
|
+
|
|
111
|
+
## Applicable versions
|
|
112
|
+
|
|
113
|
+
`session.cookie_samesite` requires PHP 7.3 or later — on an earlier version
|
|
114
|
+
this is a version-upgrade finding rather than a configuration omission. The
|
|
115
|
+
other directives and the `session_regenerate_id()` ordering guidance are
|
|
116
|
+
current php.net manual guidance as of this review; re-verify against the
|
|
117
|
+
live manual page before citing behavior for a PHP version outside current
|
|
118
|
+
support.
|
|
119
|
+
|
|
120
|
+
## Sources
|
|
121
|
+
|
|
122
|
+
- [PHP Manual — Session Management Basics](https://www.php.net/manual/en/features.session.security.management.php) — supports the `session_regenerate_id()` ordering requirement around privilege elevation, the periodic-regeneration guidance, and the "does not delete outdated sessions by default" caution.
|
|
123
|
+
- [PHP Manual — Securing Session INI Settings](https://www.php.net/manual/en/session.security.ini.php) — supports `session.use_strict_mode` being mandatory-but-disabled-by-default, `session.cookie_httponly`, `session.cookie_secure`, and `session.cookie_samesite` (PHP 7.3+) directive behavior.
|
|
124
|
+
- [PHP Manual — Sessions and Security (overview)](https://www.php.net/manual/en/session.security.php) — top-level page framing session security as core to web application security and pointing to the two subsection pages above.
|
|
125
|
+
|
|
126
|
+
Last verified: 2026-07-16.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Unserialize object injection
|
|
2
|
+
|
|
3
|
+
## Why this matters
|
|
4
|
+
|
|
5
|
+
`unserialize()` does not just decode data — it can rebuild arbitrary objects
|
|
6
|
+
and then automatically hand them control. If the serialized string an
|
|
7
|
+
attacker controls names a class the application has autoloaded (directly or
|
|
8
|
+
transitively), reconstructing that object can invoke its magic methods with
|
|
9
|
+
attacker-influenced property values, and one of those methods reaching a
|
|
10
|
+
dangerous sink (a file write, a command, a second `unserialize()`, a query)
|
|
11
|
+
is enough to turn a data-parsing call into code execution. This is PHP
|
|
12
|
+
object injection, and php.net's own manual treats it as unconditional: there
|
|
13
|
+
is no safe way to call `unserialize()` on untrusted input, only safer
|
|
14
|
+
alternatives to use instead.
|
|
15
|
+
|
|
16
|
+
## NORMATIVE: php.net's unconditional caution
|
|
17
|
+
|
|
18
|
+
Per the php.net manual page for `unserialize()`:
|
|
19
|
+
|
|
20
|
+
- "Do not pass untrusted user input to `unserialize()` regardless of the
|
|
21
|
+
`options` value of `allowed_classes`. Unserialization can result in code
|
|
22
|
+
being loaded and executed due to object instantiation and autoloading, and
|
|
23
|
+
a malicious user may be able to exploit this."
|
|
24
|
+
- The manual's stated alternative for untrusted data interchange is "a safe,
|
|
25
|
+
standard data interchange format such as JSON (via `json_decode()` and
|
|
26
|
+
`json_encode()`)."
|
|
27
|
+
- After successfully reconstructing an object, PHP "will automatically
|
|
28
|
+
attempt to call the `__unserialize()` or `__wakeup()` methods (if one
|
|
29
|
+
exists)" — this invocation happens as part of `unserialize()` itself, not
|
|
30
|
+
as a separate step a caller can skip.
|
|
31
|
+
|
|
32
|
+
This is the single controlling fact for this review: the caution is not
|
|
33
|
+
scoped to "when `allowed_classes` is absent" — it applies **regardless of**
|
|
34
|
+
that option's value. A review must not treat `allowed_classes` as the fix.
|
|
35
|
+
|
|
36
|
+
## RECOMMENDATION: what `allowed_classes` actually does, and does not do
|
|
37
|
+
|
|
38
|
+
`allowed_classes` restricts which class names `unserialize()` is willing to
|
|
39
|
+
instantiate (e.g. `unserialize($string, ['allowed_classes' => false])`
|
|
40
|
+
instantiates no objects at all, converting them to `__PHP_Incomplete_Class`
|
|
41
|
+
instead). Use it as defense-in-depth when a design genuinely requires
|
|
42
|
+
`unserialize()` over data that cannot be fully untrusted-input-free, but do
|
|
43
|
+
not present it to engineers as a fix for untrusted-input reachability — the
|
|
44
|
+
manual's caution stands regardless of the option, and per user-contributed
|
|
45
|
+
notes on the same manual page, `allowed_classes` does not follow class
|
|
46
|
+
inheritance (allowing an interface does not allow its implementers, and
|
|
47
|
+
subclasses of an allowed class do not automatically pass).
|
|
48
|
+
|
|
49
|
+
## The wider magic-method attack surface: `__destruct()` too
|
|
50
|
+
|
|
51
|
+
Object-injection ("PHP Object Injection" / gadget-chain) exploitation is not
|
|
52
|
+
limited to `__wakeup()`/`__unserialize()`. Any class instantiated by the
|
|
53
|
+
`unserialize()` call is a live PHP object with its full lifecycle ahead of
|
|
54
|
+
it, including destruction. Per the php.net manual for destructors: "The
|
|
55
|
+
destructor method will be called as soon as there are no other references to
|
|
56
|
+
a particular object, or in any order during the shutdown sequence." This
|
|
57
|
+
means a reconstructed object with attacker-controlled properties can trigger
|
|
58
|
+
consequential logic in its `__destruct()` even if it has no `__wakeup()` or
|
|
59
|
+
`__unserialize()` at all — including at request shutdown, when no other code
|
|
60
|
+
runs after it. Two destructor-execution details a reviewer should carry
|
|
61
|
+
into any gadget-chain analysis, per the same page:
|
|
62
|
+
`__destruct()` calls made during shutdown happen "in any order" (no
|
|
63
|
+
guaranteed sequence among unrelated objects), and destructors are called
|
|
64
|
+
even when the script stops via `exit()`. When reviewing a class reachable
|
|
65
|
+
from `unserialize()`, check `__wakeup()`, `__unserialize()`, and
|
|
66
|
+
`__destruct()` — all three are automatic, attacker-triggerable entry points
|
|
67
|
+
once the object exists.
|
|
68
|
+
|
|
69
|
+
## RECOMMENDATION: prefer `json_decode()` for untrusted data
|
|
70
|
+
|
|
71
|
+
Match the manual's own stated remediation: for any data interchange that
|
|
72
|
+
crosses a trust boundary (request body, query string, cookie, cache key
|
|
73
|
+
sourced from user input, a queue message an external party can influence),
|
|
74
|
+
use `json_decode()`/`json_encode()` rather than `serialize()`/`unserialize()`.
|
|
75
|
+
If a legacy format genuinely requires PHP's native serialization for
|
|
76
|
+
internal, fully-trusted data only, confirm the value never round-trips
|
|
77
|
+
through anything a client can influence, and consider the manual's mention
|
|
78
|
+
of `hash_hmac()`-based integrity verification for data an application stores
|
|
79
|
+
externally and later reads back, so that tampering can be detected before
|
|
80
|
+
`unserialize()` (or `json_decode()`) is ever called on it.
|
|
81
|
+
|
|
82
|
+
## Reviewer evidence criteria
|
|
83
|
+
|
|
84
|
+
For each `unserialize()` call site:
|
|
85
|
+
|
|
86
|
+
- Identify the exact source of the string passed in. Untrusted sources
|
|
87
|
+
include request parameters, headers, cookies, uploaded file contents,
|
|
88
|
+
values read back from a cache/session/queue backend that a client can
|
|
89
|
+
influence, and any database column a client-facing write path can reach.
|
|
90
|
+
- If the source is untrusted, this is a blocking finding regardless of
|
|
91
|
+
whether `allowed_classes` is set, per the manual's unconditional caution.
|
|
92
|
+
- If `allowed_classes` is present, do not close the finding on that basis;
|
|
93
|
+
note it as partial defense-in-depth only, and still require remediation
|
|
94
|
+
toward `json_decode()` or a fully-trusted data path.
|
|
95
|
+
- For any class the call could instantiate (open allowlist, `false`, or a
|
|
96
|
+
named list), check for `__wakeup()`, `__unserialize()`, and `__destruct()`
|
|
97
|
+
definitions in that class and its parents; if any exists, name it as a
|
|
98
|
+
live attack-surface entry point in the finding, not just a theoretical one.
|
|
99
|
+
- Confirm the recommended remediation is `json_decode()`/`json_encode()`
|
|
100
|
+
(or an equivalent non-object-instantiating format) unless the review
|
|
101
|
+
independently confirms native PHP serialization is required and the data
|
|
102
|
+
never crosses a trust boundary.
|
|
103
|
+
|
|
104
|
+
## Applicable versions
|
|
105
|
+
|
|
106
|
+
The `unserialize()` caution, the automatic `__unserialize()`/`__wakeup()`
|
|
107
|
+
invocation, and the `allowed_classes` behavior described above are current
|
|
108
|
+
php.net manual guidance as of this review; the destructor shutdown-ordering
|
|
109
|
+
and `exit()` behavior is also current manual guidance, with the manual
|
|
110
|
+
separately noting that destructors are not run on shutdown caused by a fatal
|
|
111
|
+
error as of PHP 5.3.10. Re-verify against the live manual pages before citing
|
|
112
|
+
an exact figure for a PHP version outside current support, since documented
|
|
113
|
+
behavior can be refined between manual revisions.
|
|
114
|
+
|
|
115
|
+
## Sources
|
|
116
|
+
|
|
117
|
+
- [PHP Manual — `unserialize()`](https://www.php.net/manual/en/function.unserialize.php) — supports the unconditional caution against passing untrusted input to `unserialize()` regardless of `allowed_classes`, the automatic `__unserialize()`/`__wakeup()` invocation on reconstructed objects, and the `json_decode()`/`json_encode()` remediation recommendation.
|
|
118
|
+
- [PHP Manual — Destructors](https://www.php.net/manual/en/language.oop5.decon.php) — supports the `__destruct()` invocation timing (on last reference removal or in any order during shutdown), invocation even after `exit()`, and the PHP 5.3.10 fatal-error exception to shutdown-time destructor execution.
|
|
119
|
+
- [OWASP Top 10:2021 — A08:2021 Software and Data Integrity Failures](https://owasp.org/Top10/2021/A08_2021-Software_and_Data_Integrity_Failures/index.html) — supports the OWASP category mapping for insecure-deserialization findings (CWE-502: Deserialization of Untrusted Data is listed among this category's notable weaknesses). OWASP has since published a Top 10:2025 edition (https://owasp.org/Top10/2025/) that renumbers this category to A08:2025 – Software or Data Integrity Failures and moves Injection to A05:2025; cite the specific edition and number in any finding rather than assuming 2021 numbering is still current.
|
|
120
|
+
|
|
121
|
+
Last verified: 2026-07-16.
|