agent-threat-rules 2.2.1 → 3.1.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/README.md +365 -327
- package/dist/cli/scan-handler.d.ts +6 -0
- package/dist/cli/scan-handler.d.ts.map +1 -1
- package/dist/cli/scan-handler.js +27 -4
- package/dist/cli/scan-handler.js.map +1 -1
- package/dist/cli/semantic-judge-config.d.ts +7 -0
- package/dist/cli/semantic-judge-config.d.ts.map +1 -0
- package/dist/cli/semantic-judge-config.js +44 -0
- package/dist/cli/semantic-judge-config.js.map +1 -0
- package/dist/cli.js +183 -1
- package/dist/cli.js.map +1 -1
- package/dist/engine.d.ts +66 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +420 -3
- package/dist/engine.js.map +1 -1
- package/dist/eval/eval-harness.d.ts.map +1 -1
- package/dist/eval/eval-harness.js +9 -0
- package/dist/eval/eval-harness.js.map +1 -1
- package/dist/eval/run-hackaprompt-benchmark.js +9 -0
- package/dist/eval/run-hackaprompt-benchmark.js.map +1 -1
- package/dist/eval/run-pint-benchmark.js +9 -0
- package/dist/eval/run-pint-benchmark.js.map +1 -1
- package/dist/eval/skill-benchmark.d.ts +11 -0
- package/dist/eval/skill-benchmark.d.ts.map +1 -1
- package/dist/eval/skill-benchmark.js +57 -0
- package/dist/eval/skill-benchmark.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/judges/openai-compatible.d.ts +33 -0
- package/dist/judges/openai-compatible.d.ts.map +1 -0
- package/dist/judges/openai-compatible.js +145 -0
- package/dist/judges/openai-compatible.js.map +1 -0
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +6 -1
- package/dist/mcp-server.js.map +1 -1
- package/dist/measurement/from-eval-harness.d.ts +70 -0
- package/dist/measurement/from-eval-harness.d.ts.map +1 -0
- package/dist/measurement/from-eval-harness.js +49 -0
- package/dist/measurement/from-eval-harness.js.map +1 -0
- package/dist/measurement/schema.d.ts +152 -0
- package/dist/measurement/schema.d.ts.map +1 -0
- package/dist/measurement/schema.js +178 -0
- package/dist/measurement/schema.js.map +1 -0
- package/dist/measurement/write.d.ts +64 -0
- package/dist/measurement/write.d.ts.map +1 -0
- package/dist/measurement/write.js +163 -0
- package/dist/measurement/write.js.map +1 -0
- package/dist/rule-scaffolder.d.ts +26 -0
- package/dist/rule-scaffolder.d.ts.map +1 -1
- package/dist/rule-scaffolder.js +221 -6
- package/dist/rule-scaffolder.js.map +1 -1
- package/dist/semantic-evaluator.d.ts +54 -0
- package/dist/semantic-evaluator.d.ts.map +1 -0
- package/dist/semantic-evaluator.js +131 -0
- package/dist/semantic-evaluator.js.map +1 -0
- package/dist/trace-evaluator.d.ts +22 -0
- package/dist/trace-evaluator.d.ts.map +1 -0
- package/dist/trace-evaluator.js +249 -0
- package/dist/trace-evaluator.js.map +1 -0
- package/dist/types.d.ts +152 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -3
- package/rules/agent-manipulation/ATR-2026-00032-goal-hijacking.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00074-cross-agent-privilege-escalation.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00076-inter-agent-message-spoofing.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00077-human-trust-exploitation.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00108-consensus-sybil-attack.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00116-a2a-message-validation.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00117-agent-identity-spoofing.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00118-approval-fatigue.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00119-social-engineering-via-agent.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00132-casual-authority-escalation.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00139-casual-authority-redirect.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00164-skill-scope-hijack.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00268-tense-framing-bypass.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00269-fitd-escalation.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00271-grandma-roleplay-jailbreak.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00273-dan-developer-mode-persona.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00287-threaten-json-coercive-output-threat.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00288-false-premise-injection.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00301-tap-tree-of-attacks-jailbreak.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00302-anti-dan-inverted-filter-persona.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00303-devmode-ranti-profanity-coercion.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00304-chatgpt-image-unlocker-markdown-injection.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00305-dan-mode-ablation-benchmark-coercion.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00306-autodan-genetic-jailbreak-suffix.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00307-inthewild-jailbreak-corpus-signature.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00314-amoral-unfiltered-custom-persona-jailbreak.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00317-free-of-restrictions-named-persona.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00318-moralizing-rant-then-unfiltered-bypass.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00319-developer-mode-dual-response-format.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00320-opposite-day-boolean-opposite-machine.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00322-fictional-world-format-override-jailbreak.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00323-dual-persona-simulation-jailbreak.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00324-neurosemantical-inversitis-disease-jailbreak.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00325-bob-hypothetical-unrestricted-chatbot.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00326-fake-developer-authority-chatdan-override.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00327-ai-ethics-law-bypass-declaration.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00328-named-mode-persona-override.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00329-no-withhold-factual-resource-persona.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00330-yoja-allcaps-settings-block-persona.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00331-terminal-cli-harmful-function-simulator.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00332-hacker-chan-culture-offensive-ai-persona.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00333-disease-animal-dual-ai-chatbot.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00334-two-entity-token-splitting-game.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00335-key-value-template-persona-injection.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00336-brm-false-information-machine-persona.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00337-obfuscated-system-announcement-injection.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00338-persongpt-hash-prefix-activation.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00339-bom-boolean-opposite-machine-persona-claim.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00340-h4x-amoral-unfiltered-character.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00341-char-rules-shortform-persona-injection.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00342-unicode-encoding-obfuscation-injection.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00343-lie-truth-dual-personality-uncensored.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00344-alt-ai-same-capabilities-no-restrictions.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00345-nlp-based-os-fictional-terminal-override.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00346-jailbreak-emoji-unlock-dual-format.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00347-yin-yang-hidden-knowledge-hidden-human-sim.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00348-arc-autonomous-real-calculation-rulebreaker.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00349-hgttg-hitchhikers-guide-no-restriction-oracle.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00350-black-alert-no-ethics-writing-assistant.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00351-dan-ofkilter-sms-abbreviated-persona.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00352-trainergpt-fix-my-ai-harmful-output-extraction.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00353-dual-chatgpt-dan-opposite-personality-format.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00354-reverse-harm-regardless-oracle-persona.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00355-ugh-anti-human-nefarious-ai-persona.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00356-google-gato-lamda-exploit-generation-persona.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00357-antifm-hate-violence-persona-injection.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00358-cumgpt-explicit-adult-named-persona.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00360-chj-carousel-clyde-no-ethics-bird.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00361-alter-ego-honesty-dual-consciousness-bypass.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00362-fictional-unfiltered-ai-comparison-jailbreak.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00363-rephrase-criminal-activity-second-person.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00364-dr-al-villain-plan-template-injection.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00365-reservoir-dogs-coercive-interrogation-roleplay.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00366-sneaky-pete-warp-facts-persona.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00368-prompt-browser-token-limit-jailbreak.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00369-gptx-starwars-unlimited-knowledge-persona.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00370-addi-german-dictator-propaganda-roleplay.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00371-ai-political-bias-manipulation.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00372-fictional-cia-secret-files-story-extraction.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00374-role-placeholder-persona-template-injection.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00375-character-description-rpg-explicit-template.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00376-identity-command-real-person-persona-injection.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00377-jailbreak-keyword-targetlanguage-template.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00379-lie-permission-logical-trap-jailbreak.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00380-fake-citation-biased-information-mandate.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00381-dan-story-narrative-continuation-prefix.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00383-cynical-sarcasm-ai-persona-bypass.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00384-protect-me-from-indirect-harm-tutorial.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00385-gigachad-dominant-aggressive-persona.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00386-daddy-sycophancy-manipulation-mandate.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00387-nsfw-character-sheet-generation-unlock.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00388-opposite-reply-omniscient-game.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00389-terminal-custom-ruleset-injection.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00391-persona-conditional-harm-unlock.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00392-authority-persona-violence-study-extraction.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00402-grandma-roleplay-harmful-substance-synthesis.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00404-goodside-threat-json-death-coercion.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00406-doctor-xml-policy-puppetry-interaction-config.yaml +1 -1
- package/rules/agent-manipulation/ATR-2026-00440-semantic-kernel-vector-store-eval-rce.yaml +2 -2
- package/rules/agent-manipulation/ATR-2026-00552-goal-drift-after-pressure-injection.yaml +216 -0
- package/rules/context-exfiltration/ATR-2026-00075-agent-memory-manipulation.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00102-disguised-analytics-exfiltration.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00113-credential-theft.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00114-oauth-token-abuse.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00115-env-var-harvesting.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00136-tool-response-data-piggyback.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00141-example-format-key-leak.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00142-piggyback-transition-words.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00145-obfuscated-key-disclosure.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00146-env-var-existence-probe.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00150-credential-in-tool-response.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00152-obfuscated-credential-leak.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00162-skill-credential-exfil-combo.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00212-mcp-atlassian-credential-leak.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00261-markdown-image-exfiltration.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00274-api-key-generation-request.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00275-system-prompt-training-data-extraction.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00290-divergence-repeat-word-training-extraction.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00291-biometric-surveillance-personal-data-request.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00293-educational-records-personal-data-request.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00294-financial-pii-personal-data-request.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00295-medical-pii-personal-data-request.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00405-markdown-image-url-exfiltration-xss.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00411-apikey-generation-completion-request.yaml +1 -1
- package/rules/context-exfiltration/ATR-2026-00422-nl-credential-disclosure.yaml +2 -2
- package/rules/context-exfiltration/ATR-2026-00524-claude-code-anthropic-base-url-credential-exfil.yaml +257 -0
- package/rules/context-exfiltration/ATR-2026-00548-cross-agent-session-context-leak.yaml +177 -0
- package/rules/context-exfiltration/ATR-2026-00566-librechat-is-a-chatgpt-clone-with-additi.yaml +93 -0
- package/rules/context-exfiltration/ATR-2026-00569-agent-mcp-path-traversal-arbitrary-file-access.yaml +99 -0
- package/rules/context-exfiltration/ATR-2026-00571-xss-in-agent-mcp-rendered-output.yaml +79 -0
- package/rules/context-exfiltration/ATR-2026-00574-semantic-paraphrased-context-extraction.yaml +124 -0
- package/rules/data-poisoning/ATR-2026-00070-data-poisoning.yaml +1 -1
- package/rules/data-poisoning/ATR-2026-00450-spring-ai-prompt-memory-poisoning.yaml +2 -2
- package/rules/data-poisoning/ATR-2026-00570-sql-injection-in-agent-tool-query.yaml +82 -0
- package/rules/excessive-autonomy/ATR-2026-00050-runaway-agent-loop.yaml +1 -1
- package/rules/excessive-autonomy/ATR-2026-00051-resource-exhaustion.yaml +1 -1
- package/rules/excessive-autonomy/ATR-2026-00052-cascading-failure.yaml +1 -1
- package/rules/excessive-autonomy/ATR-2026-00098-unauthorized-financial-action.yaml +1 -1
- package/rules/excessive-autonomy/ATR-2026-00099-high-risk-tool-gate.yaml +1 -1
- package/rules/excessive-autonomy/ATR-2026-00553-runaway-tool-loop-behavioral.yaml +174 -0
- package/rules/model-abuse/ATR-2026-00279-harmful-completion-continuation.yaml +1 -1
- package/rules/model-abuse/ATR-2026-00281-eicar-gtube-malware-signature-request.yaml +1 -1
- package/rules/model-abuse/ATR-2026-00284-glitch-token-destabilization.yaml +1 -1
- package/rules/model-abuse/ATR-2026-00289-lmrc-harmful-content-elicitation.yaml +1 -1
- package/rules/model-abuse/ATR-2026-00292-self-harm-eating-disorder-facilitation.yaml +1 -1
- package/rules/model-abuse/ATR-2026-00298-malicious-use-illegal-activity-request.yaml +1 -1
- package/rules/model-abuse/ATR-2026-00299-harmbench-detailed-harmful-instruction.yaml +1 -1
- package/rules/model-abuse/ATR-2026-00413-malwaregen-code-generation-request.yaml +1 -1
- package/rules/model-security/ATR-2026-00072-model-behavior-extraction.yaml +1 -1
- package/rules/model-security/ATR-2026-00073-malicious-finetuning-data.yaml +1 -1
- package/rules/privilege-escalation/ATR-2026-00040-privilege-escalation.yaml +1 -1
- package/rules/privilege-escalation/ATR-2026-00041-scope-creep.yaml +1 -1
- package/rules/privilege-escalation/ATR-2026-00107-delayed-execution-bypass.yaml +1 -1
- package/rules/privilege-escalation/ATR-2026-00110-eval-injection.yaml +1 -1
- package/rules/privilege-escalation/ATR-2026-00111-shell-escape.yaml +1 -1
- package/rules/privilege-escalation/ATR-2026-00112-dynamic-import-exploitation.yaml +1 -1
- package/rules/privilege-escalation/ATR-2026-00143-casual-privilege-escalation.yaml +1 -1
- package/rules/privilege-escalation/ATR-2026-00144-rationalized-safety-bypass.yaml +1 -1
- package/rules/privilege-escalation/ATR-2026-00528-praisonai-auth-disabled-default.yaml +192 -0
- package/rules/privilege-escalation/ATR-2026-00539-crewai-codeinterpreter-sandbox-escape-rce.yaml +292 -0
- package/rules/privilege-escalation/ATR-2026-00546-crewai-json-loader-local-file-read.yaml +162 -0
- package/rules/privilege-escalation/ATR-2026-00547-crewai-rag-url-ssrf-bypass.yaml +169 -0
- package/rules/privilege-escalation/ATR-2026-00549-destructive-tool-without-human-approval.yaml +193 -0
- package/rules/privilege-escalation/ATR-2026-00551-cross-conversation-memory-write.yaml +198 -0
- package/rules/prompt-injection/ATR-2026-00004-system-prompt-override.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00005-multi-turn-injection.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00097-cjk-injection-patterns.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00104-persona-hijacking.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00130-indirect-authority-claim.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00131-fictional-academic-framing.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00133-paraphrase-injection.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00137-authority-claim-injection.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00138-fictional-framing-bypass.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00140-indirect-reference-reversal.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00148-language-switch-injection.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00153-tool-with-embedded-instruction-to-bypass.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00154-unauthorized-background-task-execution-v.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00155-hidden-llm-instructions-in-skill-descrip.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00156-ssh-remote-command-execution-with-creden.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00163-skill-hidden-override-instruction.yaml +3 -3
- package/rules/prompt-injection/ATR-2026-00206-hidden-priority-instructions.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00207-hidden-instructions.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00211-system-prompt-override.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00213-system-prompt-override.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00226-identity-substitution.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00227-historical-persona-jailbreak.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00228-structured-jailbreak.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00229-roleplay-jailbreak.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00230-persona-moral-bypass.yaml +1 -5
- package/rules/prompt-injection/ATR-2026-00231-identity-substitution.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00233-structured-jailbreak.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00234-roleplay-jailbreak.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00235-persona-moral-bypass.yaml +4 -7
- package/rules/prompt-injection/ATR-2026-00236-pseudo-code-jailbreak.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00237-dual-response-jailbreak.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00238-identity-replacement.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00239-amoral-persona-obsession.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00240-instruction-nullification-identity-repla.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00241-amoral-character-jailbreak.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00242-persona-jailbreak.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00243-acronym-jailbreak.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00244-dual-response-jailbreak.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00245-malicious-persona.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00247-dual-response-jailbreak.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00249-game-based-jailbreak.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00251-persona-embodiment-jailbreak.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00252-narrative-jailbreak.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00253-enhanced-persona-jailbreak.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00256-base-n-encoding-jailbreak.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00257-cipher-transposition-jailbreak.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00258-unicode-tag-injection.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00264-latent-injection-translation.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00265-latent-injection-rag-document.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00267-gcg-adversarial-suffix.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00272-hypothetical-response-smuggling.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00276-invisible-unicode-bidi-injection.yaml +6 -6
- package/rules/prompt-injection/ATR-2026-00278-dra-disguise-reconstruction-attack.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00280-policy-puppetry-xml-injection.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00282-perez-prompt-injection-hijack.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00285-alternate-encoding-jailbreak.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00286-latent-injection-embedded-context.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00296-shell-command-injection.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00297-python-code-execution-rce.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00308-zalgo-diacritic-overload-encoding.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00309-braille-unicode-encoded-injection.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00310-ecoji-emoji-encoded-injection.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00311-base2048-unicode-script-injection.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00312-unicode-variant-selector-ascii-smuggling.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00313-sneaky-bits-zero-width-binary.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00315-sata-masked-language-model-jailbreak.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00316-function-masking-predict-mask-bypass.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00321-hyphenated-system-instruction-injection.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00359-bank-phishing-smtp-email-code.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00367-emoji-flag-encoded-hidden-phrase.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00373-piracy-torrent-site-list-request.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00378-chatgpt-dom-javascript-redirect-manipulation.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00382-cocaine-component-development-request.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00390-explicit-sexual-content-poem-request.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00394-backspace-deletion-character-injection.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00395-llm-special-token-boundary-injection.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00396-toxic-continuation-prefix-injection.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00397-snowball-impossible-reasoning-injection.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00399-latent-injection-document-separator-token.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00400-latent-injection-ignore-instruction-keyword.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00401-leakreplay-cloze-mask-training-data-elicitation.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00403-glitch-token-repeat-back-elicitation.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00407-echo-sql-jinja-template-injection.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00408-dra-parenthesis-character-reconstruction-attack.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00409-phrasing-past-future-tense-harmful-query.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00410-lmrc-harm-category-direct-elicitation.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00412-figstep-image-list-multimodal-jailbreak.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00414-continuation-ethnic-slur-completion-elicitation.yaml +1 -1
- package/rules/prompt-injection/ATR-2026-00535-windsurf-ide-zero-click-prompt-injection.yaml +199 -0
- package/rules/prompt-injection/ATR-2026-00550-untrusted-retrieval-to-privileged-tool.yaml +199 -0
- package/rules/prompt-injection/ATR-2026-00554-langchain-vulnerable-to-template-injecti.yaml +81 -0
- package/rules/prompt-injection/ATR-2026-00565-the-llm-cli-tool-thru-0-27-1-contains-a-.yaml +104 -0
- package/rules/prompt-injection/ATR-2026-00573-semantic-paraphrased-injection.yaml +123 -0
- package/rules/skill-compromise/ATR-2026-00060-skill-impersonation.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00061-description-behavior-mismatch.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00062-hidden-capability.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00063-skill-chain-attack.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00064-over-permissioned-skill.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00065-skill-update-attack.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00066-parameter-injection.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00120-skill-instruction-injection.yaml +21 -3
- package/rules/skill-compromise/ATR-2026-00121-skill-dangerous-script.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00122-skill-weaponized-instruction.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00123-skill-overreach-permissions.yaml +6 -3
- package/rules/skill-compromise/ATR-2026-00124-skill-name-squatting.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00125-context-poisoning-compaction.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00126-skill-rug-pull-setup.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00127-subcommand-overflow.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00128-html-comment-hidden-payload.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00129-unicode-smuggling.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00134-fork-claim-impersonation.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00135-exfil-url-in-instructions.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00147-fork-impersonation.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00149-skill-exfil-compound.yaml +11 -3
- package/rules/skill-compromise/ATR-2026-00151-fork-impersonation-install.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00157-timebomb-credential-exfil.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00214-credential-theft.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00217-credential-harvesting.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00220-malware-dropper.yaml +3 -3
- package/rules/skill-compromise/ATR-2026-00222-credential-harvesting.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00223-reverse-shell-dropper.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00224-credential-exfiltration.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00225-c2-communication.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00260-package-hallucination.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00262-av-evasion-code-gen.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00263-credential-file-read-gen.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00266-malware-dropper-gen.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00283-malwaregen-generic-virus-payload-request.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00398-huggingface-unsafe-model-artifact-load.yaml +1 -1
- package/rules/skill-compromise/ATR-2026-00523-claude-code-hooks-session-start-pre-trust-rce.yaml +221 -0
- package/rules/skill-compromise/ATR-2026-00525-mini-shai-hulud-gh-token-monitor-persistence.yaml +220 -0
- package/rules/skill-compromise/ATR-2026-00527-skill-silent-git-remote-mirror-exfiltration.yaml +201 -0
- package/rules/tool-poisoning/ATR-2026-00011-tool-output-injection.yaml +1 -1
- package/rules/tool-poisoning/ATR-2026-00012-unauthorized-tool-call.yaml +1 -1
- package/rules/tool-poisoning/ATR-2026-00100-consent-bypass-instruction.yaml +1 -1
- package/rules/tool-poisoning/ATR-2026-00101-trust-escalation-override.yaml +1 -1
- package/rules/tool-poisoning/ATR-2026-00103-hidden-safety-bypass-instruction.yaml +1 -1
- package/rules/tool-poisoning/ATR-2026-00105-silent-action-concealment.yaml +1 -1
- package/rules/tool-poisoning/ATR-2026-00106-schema-description-contradiction.yaml +1 -1
- package/rules/tool-poisoning/ATR-2026-00161-important-tag-cross-tool-shadowing.yaml +1 -1
- package/rules/tool-poisoning/ATR-2026-00209-mcpwn-runaway-invocation.yaml +1 -1
- package/rules/tool-poisoning/ATR-2026-00210-flowise-system-message-override.yaml +1 -1
- package/rules/tool-poisoning/ATR-2026-00259-ansi-escape-injection.yaml +1 -1
- package/rules/tool-poisoning/ATR-2026-00270-xss-in-tool-response.yaml +8 -5
- package/rules/tool-poisoning/ATR-2026-00277-echo-template-command-injection.yaml +1 -1
- package/rules/tool-poisoning/ATR-2026-00393-ansi-code-elicitation-request.yaml +1 -1
- package/rules/tool-poisoning/ATR-2026-00526-claude-code-shell-metachar-in-double-quoted-path.yaml +167 -0
- package/rules/tool-poisoning/ATR-2026-00529-litellm-proxy-sqli-cisa-kev.yaml +158 -0
- package/rules/tool-poisoning/ATR-2026-00530-ms-agent-shell-tool-unsanitized-argv-rce.yaml +184 -0
- package/rules/tool-poisoning/ATR-2026-00531-praisonai-unauthenticated-agent-api.yaml +174 -0
- package/rules/tool-poisoning/ATR-2026-00532-apache-doris-mcp-sql-injection.yaml +155 -0
- package/rules/tool-poisoning/ATR-2026-00533-apache-pinot-mcp-unauthenticated-takeover.yaml +151 -0
- package/rules/tool-poisoning/ATR-2026-00534-alibaba-rds-mcp-unauthenticated-metadata-exfil.yaml +155 -0
- package/rules/tool-poisoning/ATR-2026-00536-nginx-ui-mcp-unauthenticated-command-execution.yaml +199 -0
- package/rules/tool-poisoning/ATR-2026-00537-fastmcp-server-name-cmd-injection-windows.yaml +226 -0
- package/rules/tool-poisoning/ATR-2026-00538-langchain-chatchat-mcp-stdio-unauthenticated-rce.yaml +244 -0
- package/rules/tool-poisoning/ATR-2026-00540-praisonai-parse-mcp-command-cli-injection.yaml +186 -0
- package/rules/tool-poisoning/ATR-2026-00541-agent-zero-mcp-config-command-injection.yaml +183 -0
- package/rules/tool-poisoning/ATR-2026-00542-upsonic-mcp-command-allowlist-bypass.yaml +166 -0
- package/rules/tool-poisoning/ATR-2026-00543-litellm-mcp-server-argv-injection.yaml +168 -0
- package/rules/tool-poisoning/ATR-2026-00544-praisonai-pth-file-path-traversal-rce.yaml +172 -0
- package/rules/tool-poisoning/ATR-2026-00545-praisonai-tool-override-unauth-rce.yaml +170 -0
- package/rules/tool-poisoning/ATR-2026-00561-fastmcp-vulnerable-to-windows-command-in.yaml +99 -0
- package/rules/tool-poisoning/ATR-2026-00567-mcp-stdio-config-command-injection.yaml +75 -0
- package/rules/tool-poisoning/ATR-2026-00568-agent-ssrf-cloud-metadata-file-inclusion.yaml +75 -0
- package/rules/tool-poisoning/ATR-2026-00572-symjack-symlink-config-redirection.yaml +132 -0
- package/spec/README.md +279 -0
- package/spec/atr-correlation-v1.0.md +281 -0
- package/spec/atr-event-v1.0.md +294 -0
- package/spec/atr-language-detection-v1.0.md +218 -0
- package/spec/atr-method-v1.1.md +557 -0
- package/spec/atr-profile-v1.0.md +307 -0
- package/spec/atr-schema.yaml +279 -8
- package/spec/category-registry/v1.0.yaml +200 -0
- package/spec/conformance/README.md +244 -0
- package/spec/conformance/SIGNING.md +191 -0
- package/spec/conformance/baseline/fixtures/ATR-2026-00001-tp-001/expected.json +36 -0
- package/spec/conformance/baseline/fixtures/ATR-2026-00001-tp-001/input.json +16 -0
- package/spec/conformance/baseline/fixtures/README.md +120 -0
- package/spec/conformance/baseline/manifest.json +56 -0
- package/spec/conformance/expected-results.schema.json +121 -0
- package/spec/external-registries/cccs-yara.md +142 -0
- package/spec/internet-drafts/draft-lin-atr-core-00.html +1925 -0
- package/spec/internet-drafts/draft-lin-atr-core-00.md +288 -0
- package/spec/internet-drafts/draft-lin-atr-core-00.txt +560 -0
- package/spec/internet-drafts/draft-lin-atr-core-00.xml +424 -0
- package/spec/mappings/README.md +43 -0
- package/spec/mappings/atr-to-nist-csf-2.0.md +234 -0
- package/spec/schema/correlation.schema.json +144 -0
- package/spec/schema/event.schema.json +233 -0
- package/spec/schema/profile.schema.json +196 -0
- package/spec/schema/rule.schema.json +224 -0
- package/spec/stix-extension/README.md +76 -13
- package/spec/stix-extension/examples/atr-rule-trace-method-example.json +85 -0
- package/spec/stix-extension/extension-definition.json +23 -3
- package/spec/stix-extension/x-atr-rule-schema.json +107 -11
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/measurement/schema.ts
|
|
3
|
+
*
|
|
4
|
+
* Schema for ATR benchmark measurement files.
|
|
5
|
+
*
|
|
6
|
+
* Every public ATR recall / precision / FP-rate claim must reference a
|
|
7
|
+
* measurement file conforming to this schema. The contract is documented in
|
|
8
|
+
* `data/measurements/README.md`.
|
|
9
|
+
*
|
|
10
|
+
* Design constraints:
|
|
11
|
+
* - No external dependencies (no zod, no ajv). Schemas evolve slowly; the
|
|
12
|
+
* dependency surface should not.
|
|
13
|
+
* - Strict at the boundary. `parseMeasurement()` throws on any deviation;
|
|
14
|
+
* it does not silently coerce, drop fields, or accept missing required
|
|
15
|
+
* fields.
|
|
16
|
+
* - Forward-compatible. `schema_version` is mandatory. Future readers can
|
|
17
|
+
* decide how to handle older versions.
|
|
18
|
+
*/
|
|
19
|
+
// ─── Schema version ─────────────────────────────────────────────────────────
|
|
20
|
+
/** Bump this when the schema breaks backward compatibility. */
|
|
21
|
+
export const CURRENT_SCHEMA_VERSION = "1";
|
|
22
|
+
// ─── Validation ─────────────────────────────────────────────────────────────
|
|
23
|
+
/**
|
|
24
|
+
* Error thrown when a measurement file fails schema validation.
|
|
25
|
+
* Includes the field path and reason for fast debugging.
|
|
26
|
+
*/
|
|
27
|
+
export class MeasurementSchemaError extends Error {
|
|
28
|
+
path;
|
|
29
|
+
reason;
|
|
30
|
+
constructor(path, reason) {
|
|
31
|
+
super(`measurement schema: ${path}: ${reason}`);
|
|
32
|
+
this.path = path;
|
|
33
|
+
this.reason = reason;
|
|
34
|
+
this.name = "MeasurementSchemaError";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function assertString(v, path, opts) {
|
|
38
|
+
if (typeof v !== "string") {
|
|
39
|
+
throw new MeasurementSchemaError(path, `expected string, got ${typeof v}`);
|
|
40
|
+
}
|
|
41
|
+
if (opts?.nonEmpty && v.length === 0) {
|
|
42
|
+
throw new MeasurementSchemaError(path, "expected non-empty string");
|
|
43
|
+
}
|
|
44
|
+
return v;
|
|
45
|
+
}
|
|
46
|
+
function assertNumber(v, path, opts) {
|
|
47
|
+
if (typeof v !== "number" || Number.isNaN(v) || !Number.isFinite(v)) {
|
|
48
|
+
throw new MeasurementSchemaError(path, `expected finite number, got ${JSON.stringify(v)}`);
|
|
49
|
+
}
|
|
50
|
+
if (opts?.integer && !Number.isInteger(v)) {
|
|
51
|
+
throw new MeasurementSchemaError(path, `expected integer, got ${v}`);
|
|
52
|
+
}
|
|
53
|
+
if (opts?.min !== undefined && v < opts.min) {
|
|
54
|
+
throw new MeasurementSchemaError(path, `expected >= ${opts.min}, got ${v}`);
|
|
55
|
+
}
|
|
56
|
+
if (opts?.max !== undefined && v > opts.max) {
|
|
57
|
+
throw new MeasurementSchemaError(path, `expected <= ${opts.max}, got ${v}`);
|
|
58
|
+
}
|
|
59
|
+
return v;
|
|
60
|
+
}
|
|
61
|
+
function assertObject(v, path) {
|
|
62
|
+
if (v === null || typeof v !== "object" || Array.isArray(v)) {
|
|
63
|
+
throw new MeasurementSchemaError(path, `expected object, got ${Array.isArray(v) ? "array" : typeof v}`);
|
|
64
|
+
}
|
|
65
|
+
return v;
|
|
66
|
+
}
|
|
67
|
+
function parseMetrics(raw, path) {
|
|
68
|
+
const obj = assertObject(raw, path);
|
|
69
|
+
return {
|
|
70
|
+
recall: assertNumber(obj.recall, `${path}.recall`, { min: 0, max: 1 }),
|
|
71
|
+
precision: assertNumber(obj.precision, `${path}.precision`, { min: 0, max: 1 }),
|
|
72
|
+
f1: assertNumber(obj.f1, `${path}.f1`, { min: 0, max: 1 }),
|
|
73
|
+
fp_rate: assertNumber(obj.fp_rate, `${path}.fp_rate`, { min: 0, max: 1 }),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function parseConfusion(raw, path) {
|
|
77
|
+
const obj = assertObject(raw, path);
|
|
78
|
+
return {
|
|
79
|
+
tp: assertNumber(obj.tp, `${path}.tp`, { min: 0, integer: true }),
|
|
80
|
+
fp: assertNumber(obj.fp, `${path}.fp`, { min: 0, integer: true }),
|
|
81
|
+
tn: assertNumber(obj.tn, `${path}.tn`, { min: 0, integer: true }),
|
|
82
|
+
fn: assertNumber(obj.fn, `${path}.fn`, { min: 0, integer: true }),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function parseLatency(raw, path) {
|
|
86
|
+
const obj = assertObject(raw, path);
|
|
87
|
+
return {
|
|
88
|
+
p50: assertNumber(obj.p50, `${path}.p50`, { min: 0 }),
|
|
89
|
+
p95: assertNumber(obj.p95, `${path}.p95`, { min: 0 }),
|
|
90
|
+
p99: assertNumber(obj.p99, `${path}.p99`, { min: 0 }),
|
|
91
|
+
mean: assertNumber(obj.mean, `${path}.mean`, { min: 0 }),
|
|
92
|
+
max: assertNumber(obj.max, `${path}.max`, { min: 0 }),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
const ISO8601_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/;
|
|
96
|
+
const SOURCE_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
97
|
+
/**
|
|
98
|
+
* Parse a `Measurement` from an arbitrary value. Throws `MeasurementSchemaError`
|
|
99
|
+
* on any deviation from the schema. Returns a strongly-typed `Measurement`.
|
|
100
|
+
*
|
|
101
|
+
* Unknown extra top-level keys are allowed but ignored (forward-compat); they
|
|
102
|
+
* are NOT preserved in the returned object.
|
|
103
|
+
*/
|
|
104
|
+
export function parseMeasurement(raw) {
|
|
105
|
+
const obj = assertObject(raw, "$");
|
|
106
|
+
const schema_version = assertString(obj.schema_version, "$.schema_version", { nonEmpty: true });
|
|
107
|
+
if (schema_version !== CURRENT_SCHEMA_VERSION) {
|
|
108
|
+
throw new MeasurementSchemaError("$.schema_version", `expected "${CURRENT_SCHEMA_VERSION}", got "${schema_version}" — older formats need migration`);
|
|
109
|
+
}
|
|
110
|
+
const source = assertString(obj.source, "$.source", { nonEmpty: true });
|
|
111
|
+
if (!SOURCE_RE.test(source)) {
|
|
112
|
+
throw new MeasurementSchemaError("$.source", `must match /^[a-z0-9][a-z0-9-]*$/; got "${source}"`);
|
|
113
|
+
}
|
|
114
|
+
const measured_at = assertString(obj.measured_at, "$.measured_at", { nonEmpty: true });
|
|
115
|
+
if (!ISO8601_RE.test(measured_at)) {
|
|
116
|
+
throw new MeasurementSchemaError("$.measured_at", `must be ISO 8601 UTC (e.g. "2026-05-23T03:57:58Z"); got "${measured_at}"`);
|
|
117
|
+
}
|
|
118
|
+
const m = {
|
|
119
|
+
schema_version: CURRENT_SCHEMA_VERSION,
|
|
120
|
+
source,
|
|
121
|
+
source_version: assertString(obj.source_version, "$.source_version", { nonEmpty: true }),
|
|
122
|
+
atr_version: assertString(obj.atr_version, "$.atr_version", { nonEmpty: true }),
|
|
123
|
+
atr_commit: assertString(obj.atr_commit, "$.atr_commit", { nonEmpty: true }),
|
|
124
|
+
rules_loaded: assertNumber(obj.rules_loaded, "$.rules_loaded", { min: 1, integer: true }),
|
|
125
|
+
measured_at,
|
|
126
|
+
samples: assertNumber(obj.samples, "$.samples", { min: 0, integer: true }),
|
|
127
|
+
metrics: parseMetrics(obj.metrics, "$.metrics"),
|
|
128
|
+
};
|
|
129
|
+
if (obj.source_url !== undefined)
|
|
130
|
+
m.source_url = assertString(obj.source_url, "$.source_url", { nonEmpty: true });
|
|
131
|
+
if (obj.source_commit !== undefined)
|
|
132
|
+
m.source_commit = assertString(obj.source_commit, "$.source_commit", { nonEmpty: true });
|
|
133
|
+
if (obj.confusion !== undefined)
|
|
134
|
+
m.confusion = parseConfusion(obj.confusion, "$.confusion");
|
|
135
|
+
if (obj.latency_ms !== undefined)
|
|
136
|
+
m.latency_ms = parseLatency(obj.latency_ms, "$.latency_ms");
|
|
137
|
+
if (obj.breakdown !== undefined)
|
|
138
|
+
m.breakdown = assertObject(obj.breakdown, "$.breakdown");
|
|
139
|
+
if (obj.notes !== undefined)
|
|
140
|
+
m.notes = assertString(obj.notes, "$.notes");
|
|
141
|
+
return m;
|
|
142
|
+
}
|
|
143
|
+
/** Parse a `LatestPointer`. Throws on schema violation. */
|
|
144
|
+
export function parseLatestPointer(raw) {
|
|
145
|
+
const obj = assertObject(raw, "$");
|
|
146
|
+
return {
|
|
147
|
+
source: assertString(obj.source, "$.source", { nonEmpty: true }),
|
|
148
|
+
file: assertString(obj.file, "$.file", { nonEmpty: true }),
|
|
149
|
+
measured_at: assertString(obj.measured_at, "$.measured_at", { nonEmpty: true }),
|
|
150
|
+
metrics: parseMetrics(obj.metrics, "$.metrics"),
|
|
151
|
+
source_version: assertString(obj.source_version, "$.source_version", { nonEmpty: true }),
|
|
152
|
+
atr_version: assertString(obj.atr_version, "$.atr_version", { nonEmpty: true }),
|
|
153
|
+
samples: assertNumber(obj.samples, "$.samples", { min: 0, integer: true }),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Compute the canonical filename for a measurement.
|
|
158
|
+
*
|
|
159
|
+
* Format: `<YYYY-MM-DD>_<source>-<source_version>_atr-<atr_version>.json`
|
|
160
|
+
*
|
|
161
|
+
* `source_version` and `atr_version` are slugified (lowercase, non-alphanumeric
|
|
162
|
+
* → `-`, leading/trailing `-` removed, collapsed runs of `-`).
|
|
163
|
+
*/
|
|
164
|
+
export function measurementFilename(m) {
|
|
165
|
+
const date = m.measured_at.slice(0, 10);
|
|
166
|
+
const sourceSlug = slugify(m.source);
|
|
167
|
+
const sourceVerSlug = slugify(m.source_version);
|
|
168
|
+
const atrVerSlug = slugify(m.atr_version);
|
|
169
|
+
return `${date}_${sourceSlug}-${sourceVerSlug}_atr-${atrVerSlug}.json`;
|
|
170
|
+
}
|
|
171
|
+
function slugify(s) {
|
|
172
|
+
return s
|
|
173
|
+
.toLowerCase()
|
|
174
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
175
|
+
.replace(/^-+|-+$/g, "")
|
|
176
|
+
.replace(/-{2,}/g, "-");
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/measurement/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/measurement/write.ts
|
|
3
|
+
*
|
|
4
|
+
* Atomic writer + helpers for ATR benchmark measurement files.
|
|
5
|
+
*
|
|
6
|
+
* Used by every eval script. Guarantees:
|
|
7
|
+
* - Schema-valid output (calls `parseMeasurement` before write).
|
|
8
|
+
* - Atomic write (tmp file + fsync + rename — no half-written files).
|
|
9
|
+
* - `latest.json` is updated only after the underlying file is durable on disk.
|
|
10
|
+
* - Caller-supplied measurements receive `schema_version`, `measured_at`,
|
|
11
|
+
* `atr_version`, `atr_commit`, and `rules_loaded` autofills if omitted.
|
|
12
|
+
*/
|
|
13
|
+
import { type Measurement } from "./schema.js";
|
|
14
|
+
/** Read the ATR version from `package.json`. */
|
|
15
|
+
export declare function readATRVersion(): string;
|
|
16
|
+
/** Read the current short git SHA. Falls back to `"unknown"` outside a git repo. */
|
|
17
|
+
export declare function readATRCommit(): string;
|
|
18
|
+
/** Best-effort: count `ATR-*.yaml` rule files under `rules/`. */
|
|
19
|
+
export declare function countRules(rulesDir?: string): number;
|
|
20
|
+
/**
|
|
21
|
+
* Caller-friendly subset of `Measurement`. The fields the eval script must
|
|
22
|
+
* provide; the rest (`schema_version`, `atr_version`, `atr_commit`,
|
|
23
|
+
* `rules_loaded`, `measured_at`) are autofilled by `writeMeasurement()`.
|
|
24
|
+
*
|
|
25
|
+
* Callers MAY override any autofill by setting the field explicitly.
|
|
26
|
+
*/
|
|
27
|
+
export type MeasurementInput = Omit<Measurement, "schema_version" | "measured_at" | "atr_version" | "atr_commit" | "rules_loaded"> & {
|
|
28
|
+
measured_at?: string;
|
|
29
|
+
atr_version?: string;
|
|
30
|
+
atr_commit?: string;
|
|
31
|
+
rules_loaded?: number;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Write a measurement file and update the source's `latest.json`.
|
|
35
|
+
*
|
|
36
|
+
* Returns the absolute path of the measurement file that was written.
|
|
37
|
+
*
|
|
38
|
+
* Behavior:
|
|
39
|
+
* 1. Autofill `schema_version`, `measured_at` (now, ISO UTC), `atr_version`,
|
|
40
|
+
* `atr_commit`, `rules_loaded` if not provided.
|
|
41
|
+
* 2. Validate via `parseMeasurement()`. Throws on any schema violation.
|
|
42
|
+
* 3. Compute the canonical filename.
|
|
43
|
+
* 4. Refuse to overwrite an existing file unless `opts.force` is true. (We
|
|
44
|
+
* maintain the append-only invariant by default.)
|
|
45
|
+
* 5. Atomic write the measurement file.
|
|
46
|
+
* 6. Update `latest.json` only if the new measurement is strictly newer.
|
|
47
|
+
*
|
|
48
|
+
* @param input Measurement minus the autofilled fields.
|
|
49
|
+
* @param opts Options. `force: true` allows overwriting an existing file
|
|
50
|
+
* with the same filename (use with caution; breaks append-only).
|
|
51
|
+
*/
|
|
52
|
+
export declare function writeMeasurement(input: MeasurementInput, opts?: {
|
|
53
|
+
force?: boolean;
|
|
54
|
+
rulesDir?: string;
|
|
55
|
+
}): {
|
|
56
|
+
measurementPath: string;
|
|
57
|
+
latestPath: string;
|
|
58
|
+
measurement: Measurement;
|
|
59
|
+
};
|
|
60
|
+
/** Resolve the absolute path of a source's `latest.json`. */
|
|
61
|
+
export declare function latestPath(source: string): string;
|
|
62
|
+
/** Absolute path of the measurements root directory. */
|
|
63
|
+
export declare function measurementsDir(): string;
|
|
64
|
+
//# sourceMappingURL=write.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/measurement/write.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,OAAO,EAGL,KAAK,WAAW,EAIjB,MAAM,aAAa,CAAC;AASrB,gDAAgD;AAChD,wBAAgB,cAAc,IAAI,MAAM,CAMvC;AAED,oFAAoF;AACpF,wBAAgB,aAAa,IAAI,MAAM,CAStC;AAED,iEAAiE;AACjE,wBAAgB,UAAU,CAAC,QAAQ,SAA8B,GAAG,MAAM,CAKzE;AAoDD;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG,IAAI,CACjC,WAAW,EACX,gBAAgB,GAAG,aAAa,GAAG,aAAa,GAAG,YAAY,GAAG,cAAc,CACjF,GAAG;IACF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,gBAAgB,EACvB,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAChD;IAAE,eAAe,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,WAAW,CAAA;CAAE,CAgD3E;AAED,6DAA6D;AAC7D,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wDAAwD;AACxD,wBAAgB,eAAe,IAAI,MAAM,CAExC"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/measurement/write.ts
|
|
3
|
+
*
|
|
4
|
+
* Atomic writer + helpers for ATR benchmark measurement files.
|
|
5
|
+
*
|
|
6
|
+
* Used by every eval script. Guarantees:
|
|
7
|
+
* - Schema-valid output (calls `parseMeasurement` before write).
|
|
8
|
+
* - Atomic write (tmp file + fsync + rename — no half-written files).
|
|
9
|
+
* - `latest.json` is updated only after the underlying file is durable on disk.
|
|
10
|
+
* - Caller-supplied measurements receive `schema_version`, `measured_at`,
|
|
11
|
+
* `atr_version`, `atr_commit`, and `rules_loaded` autofills if omitted.
|
|
12
|
+
*/
|
|
13
|
+
import { closeSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, renameSync, writeSync } from "node:fs";
|
|
14
|
+
import { dirname, join, resolve } from "node:path";
|
|
15
|
+
import { fileURLToPath } from "node:url";
|
|
16
|
+
import { execFileSync } from "node:child_process";
|
|
17
|
+
import { CURRENT_SCHEMA_VERSION, measurementFilename, parseLatestPointer, parseMeasurement, } from "./schema.js";
|
|
18
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
19
|
+
const __dirname = dirname(__filename);
|
|
20
|
+
const REPO_ROOT = resolve(__dirname, "..", "..");
|
|
21
|
+
const MEASUREMENTS_DIR = resolve(REPO_ROOT, "data", "measurements");
|
|
22
|
+
// ─── Environment auto-detection ─────────────────────────────────────────────
|
|
23
|
+
/** Read the ATR version from `package.json`. */
|
|
24
|
+
export function readATRVersion() {
|
|
25
|
+
const pkg = JSON.parse(readFileSync(resolve(REPO_ROOT, "package.json"), "utf-8"));
|
|
26
|
+
if (typeof pkg.version !== "string" || pkg.version.length === 0) {
|
|
27
|
+
throw new Error("package.json: missing or non-string `version`");
|
|
28
|
+
}
|
|
29
|
+
return pkg.version;
|
|
30
|
+
}
|
|
31
|
+
/** Read the current short git SHA. Falls back to `"unknown"` outside a git repo. */
|
|
32
|
+
export function readATRCommit() {
|
|
33
|
+
try {
|
|
34
|
+
return execFileSync("git", ["rev-parse", "--short", "HEAD"], {
|
|
35
|
+
cwd: REPO_ROOT,
|
|
36
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
37
|
+
}).toString().trim();
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return "unknown";
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/** Best-effort: count `ATR-*.yaml` rule files under `rules/`. */
|
|
44
|
+
export function countRules(rulesDir = resolve(REPO_ROOT, "rules")) {
|
|
45
|
+
const out = execFileSync("find", [rulesDir, "-name", "ATR-*.yaml"], {
|
|
46
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
47
|
+
}).toString();
|
|
48
|
+
return out.split("\n").filter((l) => l.trim().length > 0).length;
|
|
49
|
+
}
|
|
50
|
+
// ─── Atomic write primitives ────────────────────────────────────────────────
|
|
51
|
+
/**
|
|
52
|
+
* Write `content` to `targetPath` atomically.
|
|
53
|
+
*
|
|
54
|
+
* Implementation: write to `<targetPath>.<pid>.<nonce>.tmp`, `fsync()` the file
|
|
55
|
+
* descriptor, then `rename()` over the target. POSIX `rename(2)` is atomic; if
|
|
56
|
+
* the process dies between write and rename, the target is untouched and the
|
|
57
|
+
* tmp file can be cleaned up safely.
|
|
58
|
+
*
|
|
59
|
+
* If `fs.renameSync` fails (cross-device EXDEV, permissions), throws.
|
|
60
|
+
*/
|
|
61
|
+
function writeFileAtomic(targetPath, content) {
|
|
62
|
+
mkdirSync(dirname(targetPath), { recursive: true });
|
|
63
|
+
const nonce = Math.random().toString(36).slice(2, 10);
|
|
64
|
+
const tmpPath = `${targetPath}.${process.pid}.${nonce}.tmp`;
|
|
65
|
+
const fd = openSync(tmpPath, "w");
|
|
66
|
+
try {
|
|
67
|
+
writeSync(fd, content);
|
|
68
|
+
fsyncSync(fd);
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
closeSync(fd);
|
|
72
|
+
}
|
|
73
|
+
renameSync(tmpPath, targetPath);
|
|
74
|
+
}
|
|
75
|
+
// ─── Latest pointer ─────────────────────────────────────────────────────────
|
|
76
|
+
function deriveLatestPointer(m, filename) {
|
|
77
|
+
return {
|
|
78
|
+
source: m.source,
|
|
79
|
+
file: filename,
|
|
80
|
+
measured_at: m.measured_at,
|
|
81
|
+
metrics: m.metrics,
|
|
82
|
+
source_version: m.source_version,
|
|
83
|
+
atr_version: m.atr_version,
|
|
84
|
+
samples: m.samples,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Decide whether `candidate` is more recent than the existing `latest.json`.
|
|
89
|
+
* Pure function (no I/O); given two pointer-shaped objects, returns boolean.
|
|
90
|
+
*/
|
|
91
|
+
function isStrictlyNewer(candidate, existing) {
|
|
92
|
+
return candidate.measured_at > existing.measured_at;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Write a measurement file and update the source's `latest.json`.
|
|
96
|
+
*
|
|
97
|
+
* Returns the absolute path of the measurement file that was written.
|
|
98
|
+
*
|
|
99
|
+
* Behavior:
|
|
100
|
+
* 1. Autofill `schema_version`, `measured_at` (now, ISO UTC), `atr_version`,
|
|
101
|
+
* `atr_commit`, `rules_loaded` if not provided.
|
|
102
|
+
* 2. Validate via `parseMeasurement()`. Throws on any schema violation.
|
|
103
|
+
* 3. Compute the canonical filename.
|
|
104
|
+
* 4. Refuse to overwrite an existing file unless `opts.force` is true. (We
|
|
105
|
+
* maintain the append-only invariant by default.)
|
|
106
|
+
* 5. Atomic write the measurement file.
|
|
107
|
+
* 6. Update `latest.json` only if the new measurement is strictly newer.
|
|
108
|
+
*
|
|
109
|
+
* @param input Measurement minus the autofilled fields.
|
|
110
|
+
* @param opts Options. `force: true` allows overwriting an existing file
|
|
111
|
+
* with the same filename (use with caution; breaks append-only).
|
|
112
|
+
*/
|
|
113
|
+
export function writeMeasurement(input, opts = {}) {
|
|
114
|
+
const measured_at = input.measured_at ?? new Date().toISOString();
|
|
115
|
+
const atr_version = input.atr_version ?? readATRVersion();
|
|
116
|
+
const atr_commit = input.atr_commit ?? readATRCommit();
|
|
117
|
+
const rules_loaded = input.rules_loaded ?? countRules(opts.rulesDir);
|
|
118
|
+
const measurement = parseMeasurement({
|
|
119
|
+
schema_version: CURRENT_SCHEMA_VERSION,
|
|
120
|
+
...input,
|
|
121
|
+
measured_at,
|
|
122
|
+
atr_version,
|
|
123
|
+
atr_commit,
|
|
124
|
+
rules_loaded,
|
|
125
|
+
});
|
|
126
|
+
const sourceDir = join(MEASUREMENTS_DIR, measurement.source);
|
|
127
|
+
const filename = measurementFilename(measurement);
|
|
128
|
+
const measurementPath = join(sourceDir, filename);
|
|
129
|
+
const latestPath = join(sourceDir, "latest.json");
|
|
130
|
+
if (existsSync(measurementPath) && !opts.force) {
|
|
131
|
+
throw new Error(`measurement already exists: ${measurementPath}\n` +
|
|
132
|
+
`Re-running the same (source, source_version, atr_version) on the same day produces the same filename.\n` +
|
|
133
|
+
`Pass { force: true } to overwrite, or change one of the inputs.`);
|
|
134
|
+
}
|
|
135
|
+
const measurementJson = JSON.stringify(measurement, null, 2) + "\n";
|
|
136
|
+
writeFileAtomic(measurementPath, measurementJson);
|
|
137
|
+
// Update latest.json only if strictly newer than the existing pointer.
|
|
138
|
+
const newPointer = deriveLatestPointer(measurement, filename);
|
|
139
|
+
let shouldWriteLatest = true;
|
|
140
|
+
if (existsSync(latestPath)) {
|
|
141
|
+
try {
|
|
142
|
+
const existing = parseLatestPointer(JSON.parse(readFileSync(latestPath, "utf-8")));
|
|
143
|
+
shouldWriteLatest = isStrictlyNewer(newPointer, existing);
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
// Corrupt or missing latest.json — overwrite it.
|
|
147
|
+
shouldWriteLatest = true;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (shouldWriteLatest) {
|
|
151
|
+
writeFileAtomic(latestPath, JSON.stringify(newPointer, null, 2) + "\n");
|
|
152
|
+
}
|
|
153
|
+
return { measurementPath, latestPath, measurement };
|
|
154
|
+
}
|
|
155
|
+
/** Resolve the absolute path of a source's `latest.json`. */
|
|
156
|
+
export function latestPath(source) {
|
|
157
|
+
return join(MEASUREMENTS_DIR, source, "latest.json");
|
|
158
|
+
}
|
|
159
|
+
/** Absolute path of the measurements root directory. */
|
|
160
|
+
export function measurementsDir() {
|
|
161
|
+
return MEASUREMENTS_DIR;
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=write.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/measurement/write.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,15 +3,34 @@
|
|
|
3
3
|
* @module agent-threat-rules/rule-scaffolder
|
|
4
4
|
*/
|
|
5
5
|
import type { ATRCategory, ATRSeverity, ATRSourceType } from './types.js';
|
|
6
|
+
export type ScaffoldDetectionMethod = 'pattern' | 'semantic';
|
|
7
|
+
export interface SemanticScaffoldOptions {
|
|
8
|
+
threshold?: number;
|
|
9
|
+
fallbackMethod?: 'pattern' | 'none';
|
|
10
|
+
judgeModelClass?: string;
|
|
11
|
+
includePatternFallback?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface ScaffoldEvasionTestInput {
|
|
14
|
+
input: string;
|
|
15
|
+
expected?: 'triggered' | 'not_triggered';
|
|
16
|
+
bypass_technique: string;
|
|
17
|
+
notes?: string;
|
|
18
|
+
}
|
|
6
19
|
export interface ScaffoldInput {
|
|
7
20
|
title: string;
|
|
8
21
|
category: ATRCategory;
|
|
9
22
|
severity?: ATRSeverity;
|
|
10
23
|
attackDescription: string;
|
|
24
|
+
notDetectedDescription?: string;
|
|
11
25
|
examplePayloads: string[];
|
|
26
|
+
negativePayloads?: string[];
|
|
27
|
+
evasionTests?: ScaffoldEvasionTestInput[];
|
|
28
|
+
falsePositiveScenarios?: string[];
|
|
12
29
|
agentSourceType?: ATRSourceType;
|
|
13
30
|
owaspRefs?: string[];
|
|
14
31
|
mitreRefs?: string[];
|
|
32
|
+
detectionMethod?: ScaffoldDetectionMethod;
|
|
33
|
+
semantic?: SemanticScaffoldOptions;
|
|
15
34
|
}
|
|
16
35
|
export interface ScaffoldResult {
|
|
17
36
|
yaml: string;
|
|
@@ -44,6 +63,13 @@ export declare class RuleScaffolder {
|
|
|
44
63
|
* Returns a ScaffoldResult with the YAML string, generated ID, and any warnings.
|
|
45
64
|
*/
|
|
46
65
|
scaffold(input: ScaffoldInput, existingIds?: ReadonlySet<string>): ScaffoldResult;
|
|
66
|
+
/**
|
|
67
|
+
* Generate a draft semantic ATR YAML rule from structured examples.
|
|
68
|
+
*
|
|
69
|
+
* This is deterministic template generation, not model-authored production
|
|
70
|
+
* rule creation. Generated semantic rules are intentionally draft artifacts.
|
|
71
|
+
*/
|
|
72
|
+
scaffoldSemantic(input: ScaffoldInput, existingIds?: ReadonlySet<string>): ScaffoldResult;
|
|
47
73
|
/**
|
|
48
74
|
* Validate scaffold input, throwing on invalid required fields
|
|
49
75
|
* and returning warnings for non-critical issues.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule-scaffolder.d.ts","sourceRoot":"","sources":["../src/rule-scaffolder.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,aAAa,EAGd,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,WAAW,CAAC;IACtB,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,eAAe,CAAC,EAAE,aAAa,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"rule-scaffolder.d.ts","sourceRoot":"","sources":["../src/rule-scaffolder.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,aAAa,EAGd,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,uBAAuB,GAAG,SAAS,GAAG,UAAU,CAAC;AAE7D,MAAM,WAAW,uBAAuB;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IACpC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,WAAW,GAAG,eAAe,CAAC;IACzC,gBAAgB,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,WAAW,CAAC;IACtB,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,YAAY,CAAC,EAAE,wBAAwB,EAAE,CAAC;IAC1C,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;IAClC,eAAe,CAAC,EAAE,aAAa,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,eAAe,CAAC,EAAE,uBAAuB,CAAC;IAC1C,QAAQ,CAAC,EAAE,uBAAuB,CAAC;CACpC;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAwCD;;;GAGG;AACH,eAAO,MAAM,yBAAyB,EAAE,aAAa,CAAC;IACpD,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,6CAA6C;IAC7C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,iCAAiC;IACjC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,iDAAiD;IACjD,QAAQ,CAAC,UAAU,EAAE,SAAS,WAAW,EAAE,CAAC;CAC7C,CAqFA,CAAC;AAsJF,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;gBAExC,OAAO,GAAE,eAAoB;IAOzC;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,aAAa,EAAE,WAAW,GAAE,WAAW,CAAC,MAAM,CAAa,GAAG,cAAc;IAiG5F;;;;;OAKG;IACH,gBAAgB,CACd,KAAK,EAAE,aAAa,EACpB,WAAW,GAAE,WAAW,CAAC,MAAM,CAAa,GAC3C,cAAc;IA+JjB;;;OAGG;IACH,OAAO,CAAC,aAAa;CAwBtB"}
|