shield360 1.0.1 → 1.2.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 +392 -37
- package/dist/__tests__/build-info.test.d.ts +1 -0
- package/dist/__tests__/build-info.test.js +196 -0
- package/dist/__tests__/build-info.test.js.map +1 -0
- package/dist/__tests__/code-location.test.d.ts +1 -0
- package/dist/__tests__/code-location.test.js +180 -0
- package/dist/__tests__/code-location.test.js.map +1 -0
- package/dist/__tests__/masking.test.d.ts +1 -0
- package/dist/__tests__/masking.test.js +66 -0
- package/dist/__tests__/masking.test.js.map +1 -0
- package/dist/__tests__/pricing-claude-5.test.js +3 -0
- package/dist/__tests__/pricing-claude-5.test.js.map +1 -1
- package/dist/__tests__/register.e2e.test.d.ts +1 -0
- package/dist/__tests__/register.e2e.test.js +264 -0
- package/dist/__tests__/register.e2e.test.js.map +1 -0
- package/dist/__tests__/register.test.js +60 -0
- package/dist/__tests__/register.test.js.map +1 -1
- package/dist/agents/__tests__/agents.test.d.ts +1 -0
- package/dist/agents/__tests__/agents.test.js +529 -0
- package/dist/agents/__tests__/agents.test.js.map +1 -0
- package/dist/agents/index.d.ts +15 -0
- package/dist/agents/index.js +25 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/passport.d.ts +92 -0
- package/dist/agents/passport.js +301 -0
- package/dist/agents/passport.js.map +1 -0
- package/dist/agents/policy.d.ts +24 -0
- package/dist/agents/policy.js +93 -0
- package/dist/agents/policy.js.map +1 -0
- package/dist/agents/replay.d.ts +20 -0
- package/dist/agents/replay.js +47 -0
- package/dist/agents/replay.js.map +1 -0
- package/dist/agents/report.d.ts +30 -0
- package/dist/agents/report.js +93 -0
- package/dist/agents/report.js.map +1 -0
- package/dist/agents/types.d.ts +148 -0
- package/dist/agents/types.js +37 -0
- package/dist/agents/types.js.map +1 -0
- package/dist/agents/verifier.d.ts +33 -0
- package/dist/agents/verifier.js +276 -0
- package/dist/agents/verifier.js.map +1 -0
- package/dist/ai-security/__tests__/bench.test.d.ts +1 -0
- package/dist/ai-security/__tests__/bench.test.js +50 -0
- package/dist/ai-security/__tests__/bench.test.js.map +1 -0
- package/dist/ai-security/__tests__/checks.test.d.ts +1 -0
- package/dist/ai-security/__tests__/checks.test.js +248 -0
- package/dist/ai-security/__tests__/checks.test.js.map +1 -0
- package/dist/ai-security/__tests__/config.test.d.ts +1 -0
- package/dist/ai-security/__tests__/config.test.js +164 -0
- package/dist/ai-security/__tests__/config.test.js.map +1 -0
- package/dist/ai-security/__tests__/detection.test.d.ts +1 -0
- package/dist/ai-security/__tests__/detection.test.js +114 -0
- package/dist/ai-security/__tests__/detection.test.js.map +1 -0
- package/dist/ai-security/__tests__/fixtures.d.ts +8 -0
- package/dist/ai-security/__tests__/fixtures.js +30 -0
- package/dist/ai-security/__tests__/fixtures.js.map +1 -0
- package/dist/ai-security/__tests__/hooks.test.d.ts +1 -0
- package/dist/ai-security/__tests__/hooks.test.js +174 -0
- package/dist/ai-security/__tests__/hooks.test.js.map +1 -0
- package/dist/ai-security/__tests__/stream.test.d.ts +1 -0
- package/dist/ai-security/__tests__/stream.test.js +85 -0
- package/dist/ai-security/__tests__/stream.test.js.map +1 -0
- package/dist/ai-security/config.d.ts +94 -0
- package/dist/ai-security/config.js +241 -0
- package/dist/ai-security/config.js.map +1 -0
- package/dist/ai-security/context.d.ts +45 -0
- package/dist/ai-security/context.js +108 -0
- package/dist/ai-security/context.js.map +1 -0
- package/dist/ai-security/custom-kinds.d.ts +23 -0
- package/dist/ai-security/custom-kinds.js +97 -0
- package/dist/ai-security/custom-kinds.js.map +1 -0
- package/dist/ai-security/events.d.ts +77 -0
- package/dist/ai-security/events.js +153 -0
- package/dist/ai-security/events.js.map +1 -0
- package/dist/ai-security/hooks.d.ts +48 -0
- package/dist/ai-security/hooks.js +461 -0
- package/dist/ai-security/hooks.js.map +1 -0
- package/dist/ai-security/index.d.ts +209 -0
- package/dist/ai-security/index.js +587 -0
- package/dist/ai-security/index.js.map +1 -0
- package/dist/ai-security/injection-rules.json +1024 -0
- package/dist/ai-security/injection.d.ts +46 -0
- package/dist/ai-security/injection.js +635 -0
- package/dist/ai-security/injection.js.map +1 -0
- package/dist/ai-security/jailbreak.d.ts +38 -0
- package/dist/ai-security/jailbreak.js +73 -0
- package/dist/ai-security/jailbreak.js.map +1 -0
- package/dist/ai-security/limits.d.ts +84 -0
- package/dist/ai-security/limits.js +195 -0
- package/dist/ai-security/limits.js.map +1 -0
- package/dist/ai-security/mcp.d.ts +82 -0
- package/dist/ai-security/mcp.js +150 -0
- package/dist/ai-security/mcp.js.map +1 -0
- package/dist/ai-security/output.d.ts +107 -0
- package/dist/ai-security/output.js +390 -0
- package/dist/ai-security/output.js.map +1 -0
- package/dist/ai-security/policy.d.ts +125 -0
- package/dist/ai-security/policy.js +196 -0
- package/dist/ai-security/policy.js.map +1 -0
- package/dist/ai-security/rag.d.ts +70 -0
- package/dist/ai-security/rag.js +174 -0
- package/dist/ai-security/rag.js.map +1 -0
- package/dist/ai-security/tool-rules.json +203 -0
- package/dist/ai-security/tools.d.ts +46 -0
- package/dist/ai-security/tools.js +62 -0
- package/dist/ai-security/tools.js.map +1 -0
- package/dist/budgets/__tests__/budgets.test.d.ts +1 -0
- package/dist/budgets/__tests__/budgets.test.js +134 -0
- package/dist/budgets/__tests__/budgets.test.js.map +1 -0
- package/dist/budgets/auto.d.ts +25 -0
- package/dist/budgets/auto.js +63 -0
- package/dist/budgets/auto.js.map +1 -0
- package/dist/budgets/index.d.ts +110 -0
- package/dist/budgets/index.js +239 -0
- package/dist/budgets/index.js.map +1 -0
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/customer/__tests__/customer.test.d.ts +1 -0
- package/dist/customer/__tests__/customer.test.js +155 -0
- package/dist/customer/__tests__/customer.test.js.map +1 -0
- package/dist/customer/index.d.ts +48 -0
- package/dist/customer/index.js +132 -0
- package/dist/customer/index.js.map +1 -0
- package/dist/feedback/__tests__/feedback.test.d.ts +1 -0
- package/dist/feedback/__tests__/feedback.test.js +80 -0
- package/dist/feedback/__tests__/feedback.test.js.map +1 -0
- package/dist/feedback/index.d.ts +48 -0
- package/dist/feedback/index.js +97 -0
- package/dist/feedback/index.js.map +1 -0
- package/dist/flags/__tests__/flags.test.d.ts +1 -0
- package/dist/flags/__tests__/flags.test.js +301 -0
- package/dist/flags/__tests__/flags.test.js.map +1 -0
- package/dist/flags/client.d.ts +131 -0
- package/dist/flags/client.js +301 -0
- package/dist/flags/client.js.map +1 -0
- package/dist/flags/engine.d.ts +200 -0
- package/dist/flags/engine.js +677 -0
- package/dist/flags/engine.js.map +1 -0
- package/dist/flags/index.d.ts +4 -0
- package/dist/flags/index.js +16 -0
- package/dist/flags/index.js.map +1 -0
- package/dist/guard/__tests__/findings.test.js +28 -9
- package/dist/guard/__tests__/findings.test.js.map +1 -1
- package/dist/guard/__tests__/report.test.js +67 -0
- package/dist/guard/__tests__/report.test.js.map +1 -1
- package/dist/guard/base.d.ts +2 -0
- package/dist/guard/base.js +4 -0
- package/dist/guard/base.js.map +1 -1
- package/dist/guard/findings.d.ts +12 -2
- package/dist/guard/findings.js +19 -49
- package/dist/guard/findings.js.map +1 -1
- package/dist/guard/heartbeat.d.ts +34 -0
- package/dist/guard/heartbeat.js +83 -0
- package/dist/guard/heartbeat.js.map +1 -0
- package/dist/guard/integration.d.ts +33 -3
- package/dist/guard/integration.js +106 -32
- package/dist/guard/integration.js.map +1 -1
- package/dist/guard/pipeline.d.ts +10 -1
- package/dist/guard/pipeline.js +14 -0
- package/dist/guard/pipeline.js.map +1 -1
- package/dist/guard/report.d.ts +24 -1
- package/dist/guard/report.js +67 -18
- package/dist/guard/report.js.map +1 -1
- package/dist/index.d.ts +90 -0
- package/dist/index.js +225 -3
- package/dist/index.js.map +1 -1
- package/dist/instrumentation/__tests__/langchain-wrapper.test.js +1 -1
- package/dist/instrumentation/__tests__/langchain-wrapper.test.js.map +1 -1
- package/dist/instrumentation/anthropic/wrapper.js +4 -0
- package/dist/instrumentation/anthropic/wrapper.js.map +1 -1
- package/dist/instrumentation/mcp/wrapper.js +7 -1
- package/dist/instrumentation/mcp/wrapper.js.map +1 -1
- package/dist/instrumentation/openai/wrapper.js +6 -0
- package/dist/instrumentation/openai/wrapper.js.map +1 -1
- package/dist/masking.d.ts +42 -0
- package/dist/masking.js +197 -0
- package/dist/masking.js.map +1 -0
- package/dist/otel/__tests__/app-logs-safety.test.d.ts +1 -0
- package/dist/otel/__tests__/app-logs-safety.test.js +129 -0
- package/dist/otel/__tests__/app-logs-safety.test.js.map +1 -0
- package/dist/otel/__tests__/app-logs.test.d.ts +1 -0
- package/dist/otel/__tests__/app-logs.test.js +269 -0
- package/dist/otel/__tests__/app-logs.test.js.map +1 -0
- package/dist/otel/__tests__/log-auto.test.d.ts +1 -0
- package/dist/otel/__tests__/log-auto.test.js +125 -0
- package/dist/otel/__tests__/log-auto.test.js.map +1 -0
- package/dist/otel/__tests__/log-bridges.test.d.ts +1 -0
- package/dist/otel/__tests__/log-bridges.test.js +170 -0
- package/dist/otel/__tests__/log-bridges.test.js.map +1 -0
- package/dist/otel/__tests__/system-metrics.test.d.ts +1 -0
- package/dist/otel/__tests__/system-metrics.test.js +79 -0
- package/dist/otel/__tests__/system-metrics.test.js.map +1 -0
- package/dist/otel/app-logs.d.ts +80 -0
- package/dist/otel/app-logs.js +195 -0
- package/dist/otel/app-logs.js.map +1 -0
- package/dist/otel/build-info.d.ts +23 -0
- package/dist/otel/build-info.js +176 -0
- package/dist/otel/build-info.js.map +1 -0
- package/dist/otel/code-location.d.ts +49 -0
- package/dist/otel/code-location.js +233 -0
- package/dist/otel/code-location.js.map +1 -0
- package/dist/otel/events.d.ts +1 -0
- package/dist/otel/events.js +21 -12
- package/dist/otel/events.js.map +1 -1
- package/dist/otel/log-auto.d.ts +44 -0
- package/dist/otel/log-auto.js +200 -0
- package/dist/otel/log-auto.js.map +1 -0
- package/dist/otel/log-bridges.d.ts +54 -0
- package/dist/otel/log-bridges.js +307 -0
- package/dist/otel/log-bridges.js.map +1 -0
- package/dist/otel/system-metrics.d.ts +39 -0
- package/dist/otel/system-metrics.js +166 -0
- package/dist/otel/system-metrics.js.map +1 -0
- package/dist/otel/tracing.js +12 -1
- package/dist/otel/tracing.js.map +1 -1
- package/dist/pricing.json +100 -42
- package/dist/protect/__tests__/protect.test.d.ts +1 -0
- package/dist/protect/__tests__/protect.test.js +210 -0
- package/dist/protect/__tests__/protect.test.js.map +1 -0
- package/dist/protect/index.d.ts +103 -0
- package/dist/protect/index.js +196 -0
- package/dist/protect/index.js.map +1 -0
- package/dist/protect/mcp.d.ts +13 -0
- package/dist/protect/mcp.js +49 -0
- package/dist/protect/mcp.js.map +1 -0
- package/dist/protect/mode.d.ts +89 -0
- package/dist/protect/mode.js +134 -0
- package/dist/protect/mode.js.map +1 -0
- package/dist/rasp/__tests__/auto-http.test.d.ts +1 -0
- package/dist/rasp/__tests__/auto-http.test.js +136 -0
- package/dist/rasp/__tests__/auto-http.test.js.map +1 -0
- package/dist/rasp/__tests__/baseline.test.d.ts +1 -0
- package/dist/rasp/__tests__/baseline.test.js +86 -0
- package/dist/rasp/__tests__/baseline.test.js.map +1 -0
- package/dist/rasp/__tests__/benign-corpus.test.d.ts +1 -0
- package/dist/rasp/__tests__/benign-corpus.test.js +68 -0
- package/dist/rasp/__tests__/benign-corpus.test.js.map +1 -0
- package/dist/rasp/__tests__/capture-context.test.d.ts +1 -0
- package/dist/rasp/__tests__/capture-context.test.js +135 -0
- package/dist/rasp/__tests__/capture-context.test.js.map +1 -0
- package/dist/rasp/__tests__/code-hook.test.d.ts +1 -0
- package/dist/rasp/__tests__/code-hook.test.js +218 -0
- package/dist/rasp/__tests__/code-hook.test.js.map +1 -0
- package/dist/rasp/__tests__/config-client.test.d.ts +1 -0
- package/dist/rasp/__tests__/config-client.test.js +283 -0
- package/dist/rasp/__tests__/config-client.test.js.map +1 -0
- package/dist/rasp/__tests__/corpus.d.ts +13 -0
- package/dist/rasp/__tests__/corpus.js +111 -0
- package/dist/rasp/__tests__/corpus.js.map +1 -0
- package/dist/rasp/__tests__/custom-rules.test.d.ts +1 -0
- package/dist/rasp/__tests__/custom-rules.test.js +276 -0
- package/dist/rasp/__tests__/custom-rules.test.js.map +1 -0
- package/dist/rasp/__tests__/db-hook.test.d.ts +1 -0
- package/dist/rasp/__tests__/db-hook.test.js +438 -0
- package/dist/rasp/__tests__/db-hook.test.js.map +1 -0
- package/dist/rasp/__tests__/deception.test.d.ts +1 -0
- package/dist/rasp/__tests__/deception.test.js +567 -0
- package/dist/rasp/__tests__/deception.test.js.map +1 -0
- package/dist/rasp/__tests__/detect.test.d.ts +1 -0
- package/dist/rasp/__tests__/detect.test.js +276 -0
- package/dist/rasp/__tests__/detect.test.js.map +1 -0
- package/dist/rasp/__tests__/esm-exports.test.d.ts +1 -0
- package/dist/rasp/__tests__/esm-exports.test.js +20 -0
- package/dist/rasp/__tests__/esm-exports.test.js.map +1 -0
- package/dist/rasp/__tests__/fs-hook.test.d.ts +1 -0
- package/dist/rasp/__tests__/fs-hook.test.js +241 -0
- package/dist/rasp/__tests__/fs-hook.test.js.map +1 -0
- package/dist/rasp/__tests__/hook-contracts.test.d.ts +1 -0
- package/dist/rasp/__tests__/hook-contracts.test.js +201 -0
- package/dist/rasp/__tests__/hook-contracts.test.js.map +1 -0
- package/dist/rasp/__tests__/hook-kit.d.ts +42 -0
- package/dist/rasp/__tests__/hook-kit.js +139 -0
- package/dist/rasp/__tests__/hook-kit.js.map +1 -0
- package/dist/rasp/__tests__/http-hook.test.d.ts +1 -0
- package/dist/rasp/__tests__/http-hook.test.js +250 -0
- package/dist/rasp/__tests__/http-hook.test.js.map +1 -0
- package/dist/rasp/__tests__/iast.test.d.ts +1 -0
- package/dist/rasp/__tests__/iast.test.js +361 -0
- package/dist/rasp/__tests__/iast.test.js.map +1 -0
- package/dist/rasp/__tests__/include-hook.test.d.ts +1 -0
- package/dist/rasp/__tests__/include-hook.test.js +122 -0
- package/dist/rasp/__tests__/include-hook.test.js.map +1 -0
- package/dist/rasp/__tests__/middleware.test.d.ts +1 -0
- package/dist/rasp/__tests__/middleware.test.js +302 -0
- package/dist/rasp/__tests__/middleware.test.js.map +1 -0
- package/dist/rasp/__tests__/process-hook.test.d.ts +1 -0
- package/dist/rasp/__tests__/process-hook.test.js +238 -0
- package/dist/rasp/__tests__/process-hook.test.js.map +1 -0
- package/dist/rasp/__tests__/reporter.test.d.ts +1 -0
- package/dist/rasp/__tests__/reporter.test.js +114 -0
- package/dist/rasp/__tests__/reporter.test.js.map +1 -0
- package/dist/rasp/__tests__/route.test.d.ts +1 -0
- package/dist/rasp/__tests__/route.test.js +46 -0
- package/dist/rasp/__tests__/route.test.js.map +1 -0
- package/dist/rasp/__tests__/rule-expr.test.d.ts +1 -0
- package/dist/rasp/__tests__/rule-expr.test.js +151 -0
- package/dist/rasp/__tests__/rule-expr.test.js.map +1 -0
- package/dist/rasp/__tests__/rule-phases.test.d.ts +1 -0
- package/dist/rasp/__tests__/rule-phases.test.js +271 -0
- package/dist/rasp/__tests__/rule-phases.test.js.map +1 -0
- package/dist/rasp/__tests__/sinks-hook.test.d.ts +1 -0
- package/dist/rasp/__tests__/sinks-hook.test.js +177 -0
- package/dist/rasp/__tests__/sinks-hook.test.js.map +1 -0
- package/dist/rasp/__tests__/targets.test.d.ts +1 -0
- package/dist/rasp/__tests__/targets.test.js +82 -0
- package/dist/rasp/__tests__/targets.test.js.map +1 -0
- package/dist/rasp/__tests__/template-hook.test.d.ts +1 -0
- package/dist/rasp/__tests__/template-hook.test.js +254 -0
- package/dist/rasp/__tests__/template-hook.test.js.map +1 -0
- package/dist/rasp/__tests__/upload.test.d.ts +1 -0
- package/dist/rasp/__tests__/upload.test.js +81 -0
- package/dist/rasp/__tests__/upload.test.js.map +1 -0
- package/dist/rasp/__tests__/vpatch-engine.test.d.ts +1 -0
- package/dist/rasp/__tests__/vpatch-engine.test.js +177 -0
- package/dist/rasp/__tests__/vpatch-engine.test.js.map +1 -0
- package/dist/rasp/auto-http.d.ts +6 -0
- package/dist/rasp/auto-http.js +194 -0
- package/dist/rasp/auto-http.js.map +1 -0
- package/dist/rasp/baseline.d.ts +35 -0
- package/dist/rasp/baseline.js +91 -0
- package/dist/rasp/baseline.js.map +1 -0
- package/dist/rasp/capture.d.ts +76 -0
- package/dist/rasp/capture.js +304 -0
- package/dist/rasp/capture.js.map +1 -0
- package/dist/rasp/config-client.d.ts +122 -0
- package/dist/rasp/config-client.js +337 -0
- package/dist/rasp/config-client.js.map +1 -0
- package/dist/rasp/context.d.ts +65 -0
- package/dist/rasp/context.js +68 -0
- package/dist/rasp/context.js.map +1 -0
- package/dist/rasp/custom-rules.d.ts +68 -0
- package/dist/rasp/custom-rules.js +222 -0
- package/dist/rasp/custom-rules.js.map +1 -0
- package/dist/rasp/data/default-rules.json +199 -0
- package/dist/rasp/data/default-sinks.json +4 -0
- package/dist/rasp/data/dnslog-domains.json +11 -0
- package/dist/rasp/deception.d.ts +70 -0
- package/dist/rasp/deception.js +220 -0
- package/dist/rasp/deception.js.map +1 -0
- package/dist/rasp/detect.d.ts +68 -0
- package/dist/rasp/detect.js +671 -0
- package/dist/rasp/detect.js.map +1 -0
- package/dist/rasp/engine.d.ts +107 -0
- package/dist/rasp/engine.js +330 -0
- package/dist/rasp/engine.js.map +1 -0
- package/dist/rasp/hooks/code.d.ts +20 -0
- package/dist/rasp/hooks/code.js +334 -0
- package/dist/rasp/hooks/code.js.map +1 -0
- package/dist/rasp/hooks/db.d.ts +48 -0
- package/dist/rasp/hooks/db.js +322 -0
- package/dist/rasp/hooks/db.js.map +1 -0
- package/dist/rasp/hooks/esm.d.ts +7 -0
- package/dist/rasp/hooks/esm.js +18 -0
- package/dist/rasp/hooks/esm.js.map +1 -0
- package/dist/rasp/hooks/fs.d.ts +3 -0
- package/dist/rasp/hooks/fs.js +206 -0
- package/dist/rasp/hooks/fs.js.map +1 -0
- package/dist/rasp/hooks/http.d.ts +4 -0
- package/dist/rasp/hooks/http.js +213 -0
- package/dist/rasp/hooks/http.js.map +1 -0
- package/dist/rasp/hooks/include.d.ts +9 -0
- package/dist/rasp/hooks/include.js +79 -0
- package/dist/rasp/hooks/include.js.map +1 -0
- package/dist/rasp/hooks/marks.d.ts +2 -0
- package/dist/rasp/hooks/marks.js +16 -0
- package/dist/rasp/hooks/marks.js.map +1 -0
- package/dist/rasp/hooks/process.d.ts +22 -0
- package/dist/rasp/hooks/process.js +191 -0
- package/dist/rasp/hooks/process.js.map +1 -0
- package/dist/rasp/hooks/sinks.d.ts +54 -0
- package/dist/rasp/hooks/sinks.js +329 -0
- package/dist/rasp/hooks/sinks.js.map +1 -0
- package/dist/rasp/hooks/template.d.ts +21 -0
- package/dist/rasp/hooks/template.js +152 -0
- package/dist/rasp/hooks/template.js.map +1 -0
- package/dist/rasp/iast-rules.d.ts +82 -0
- package/dist/rasp/iast-rules.js +240 -0
- package/dist/rasp/iast-rules.js.map +1 -0
- package/dist/rasp/iast-scope.d.ts +29 -0
- package/dist/rasp/iast-scope.js +54 -0
- package/dist/rasp/iast-scope.js.map +1 -0
- package/dist/rasp/iast.d.ts +81 -0
- package/dist/rasp/iast.js +272 -0
- package/dist/rasp/iast.js.map +1 -0
- package/dist/rasp/index.d.ts +52 -0
- package/dist/rasp/index.js +280 -0
- package/dist/rasp/index.js.map +1 -0
- package/dist/rasp/lexers.d.ts +32 -0
- package/dist/rasp/lexers.js +444 -0
- package/dist/rasp/lexers.js.map +1 -0
- package/dist/rasp/middleware.d.ts +155 -0
- package/dist/rasp/middleware.js +568 -0
- package/dist/rasp/middleware.js.map +1 -0
- package/dist/rasp/model-output.d.ts +14 -0
- package/dist/rasp/model-output.js +107 -0
- package/dist/rasp/model-output.js.map +1 -0
- package/dist/rasp/normalize.d.ts +23 -0
- package/dist/rasp/normalize.js +140 -0
- package/dist/rasp/normalize.js.map +1 -0
- package/dist/rasp/reporter.d.ts +60 -0
- package/dist/rasp/reporter.js +230 -0
- package/dist/rasp/reporter.js.map +1 -0
- package/dist/rasp/rule-expr.d.ts +236 -0
- package/dist/rasp/rule-expr.js +1253 -0
- package/dist/rasp/rule-expr.js.map +1 -0
- package/dist/rasp/template.d.ts +53 -0
- package/dist/rasp/template.js +336 -0
- package/dist/rasp/template.js.map +1 -0
- package/dist/rasp/types.d.ts +110 -0
- package/dist/rasp/types.js +51 -0
- package/dist/rasp/types.js.map +1 -0
- package/dist/rasp/vpatch.d.ts +55 -0
- package/dist/rasp/vpatch.js +120 -0
- package/dist/rasp/vpatch.js.map +1 -0
- package/dist/register.js +52 -11
- package/dist/register.js.map +1 -1
- package/dist/semantic-convention.d.ts +2 -0
- package/dist/semantic-convention.js +5 -0
- package/dist/semantic-convention.js.map +1 -1
- package/dist/types.d.ts +96 -0
- package/dist/zero-code.d.ts +8 -0
- package/dist/zero-code.js +38 -0
- package/dist/zero-code.js.map +1 -0
- package/package.json +18 -2
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
/**
|
|
37
|
+
* Every sink hook through the shared hook contract (hook-kit.ts). Triggers
|
|
38
|
+
* are the harmless ones the hooks' own tests use.
|
|
39
|
+
*/
|
|
40
|
+
const cp = require("child_process");
|
|
41
|
+
const fs = require("fs");
|
|
42
|
+
const http = require("http");
|
|
43
|
+
const vm = require("vm");
|
|
44
|
+
const os_1 = require("os");
|
|
45
|
+
const path_1 = require("path");
|
|
46
|
+
const detect = __importStar(require("../detect"));
|
|
47
|
+
const code_1 = require("../hooks/code");
|
|
48
|
+
const db_1 = require("../hooks/db");
|
|
49
|
+
const fs_1 = require("../hooks/fs");
|
|
50
|
+
const http_1 = require("../hooks/http");
|
|
51
|
+
const process_1 = require("../hooks/process");
|
|
52
|
+
const template_1 = require("../hooks/template");
|
|
53
|
+
const template = __importStar(require("../template"));
|
|
54
|
+
const hook_kit_1 = require("./hook-kit");
|
|
55
|
+
const req = (value) => ({ value, key: 'query.q', source: 'request' });
|
|
56
|
+
(0, hook_kit_1.describeHookContract)({
|
|
57
|
+
name: 'child_process',
|
|
58
|
+
install: process_1.installProcessHooks,
|
|
59
|
+
uninstall: process_1.uninstallProcessHooks,
|
|
60
|
+
replaced: process_1.PROCESS_APIS.map((key) => ({ owner: cp, key })),
|
|
61
|
+
outer: { owner: cp, key: 'execSync' },
|
|
62
|
+
trigger: () => cp.execSync('echo ok; echo rasp-test'),
|
|
63
|
+
inputs: [req('ok; echo rasp-test')],
|
|
64
|
+
detector: { module: detect, name: 'detectCommand' },
|
|
65
|
+
attack: 'command_injection',
|
|
66
|
+
});
|
|
67
|
+
let dir = '';
|
|
68
|
+
(0, hook_kit_1.describeHookContract)({
|
|
69
|
+
name: 'fs',
|
|
70
|
+
install: fs_1.installFsHooks,
|
|
71
|
+
uninstall: fs_1.uninstallFsHooks,
|
|
72
|
+
replaced: ['readFile', 'readFileSync', 'writeFile', 'writeFileSync', 'openSync', 'rename'].map((key) => ({ owner: fs, key })),
|
|
73
|
+
outer: { owner: fs, key: 'readFileSync' },
|
|
74
|
+
trigger: () => fs.readFileSync(`${dir}/child/../escape.txt`, 'utf8'),
|
|
75
|
+
inputs: [req('../escape.txt')],
|
|
76
|
+
detector: { module: detect, name: 'detectPath' },
|
|
77
|
+
attack: 'path_traversal',
|
|
78
|
+
beforeEach: () => {
|
|
79
|
+
dir = fs.mkdtempSync((0, path_1.join)((0, os_1.tmpdir)(), 'rasp-kit-'));
|
|
80
|
+
fs.mkdirSync((0, path_1.join)(dir, 'child'));
|
|
81
|
+
fs.writeFileSync((0, path_1.join)(dir, 'escape.txt'), 'fixture');
|
|
82
|
+
},
|
|
83
|
+
afterEach: () => fs.rmSync(dir, { recursive: true, force: true }),
|
|
84
|
+
});
|
|
85
|
+
// Nothing listens on the discard port, and the request is destroyed at once.
|
|
86
|
+
const local = 'http://127.0.0.1:9/fixture';
|
|
87
|
+
(0, hook_kit_1.describeHookContract)({
|
|
88
|
+
name: 'outbound http',
|
|
89
|
+
install: () => (0, http_1.installHttpHooks)({ alwaysAllowedHosts: [] }),
|
|
90
|
+
uninstall: http_1.uninstallHttpHooks,
|
|
91
|
+
replaced: [
|
|
92
|
+
{ owner: http, key: 'request' },
|
|
93
|
+
{ owner: http, key: 'get' },
|
|
94
|
+
],
|
|
95
|
+
trigger: () => {
|
|
96
|
+
const r = http.request(local);
|
|
97
|
+
r.on('error', () => undefined);
|
|
98
|
+
r.destroy();
|
|
99
|
+
},
|
|
100
|
+
inputs: [req(local)],
|
|
101
|
+
detector: { module: detect, name: 'detectSsrf' },
|
|
102
|
+
attack: 'ssrf',
|
|
103
|
+
});
|
|
104
|
+
const input = "' OR '1'='1";
|
|
105
|
+
class FakeClient {
|
|
106
|
+
query(...values) {
|
|
107
|
+
return values.length;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const pg = { Client: FakeClient };
|
|
111
|
+
(0, hook_kit_1.describeHookContract)({
|
|
112
|
+
name: 'database (pg)',
|
|
113
|
+
install: () => {
|
|
114
|
+
(0, db_1.patchPg)(pg);
|
|
115
|
+
return true;
|
|
116
|
+
},
|
|
117
|
+
uninstall: () => (0, db_1.unpatchPg)(pg),
|
|
118
|
+
replaced: [{ owner: FakeClient.prototype, key: 'query' }],
|
|
119
|
+
trigger: () => new FakeClient().query(`SELECT * FROM products WHERE name = '${input}'`),
|
|
120
|
+
inputs: [req(input)],
|
|
121
|
+
detector: { module: detect, name: 'detectSql' },
|
|
122
|
+
attack: 'sql_injection',
|
|
123
|
+
});
|
|
124
|
+
(0, hook_kit_1.describeHookContract)({
|
|
125
|
+
name: 'code',
|
|
126
|
+
install: code_1.installCodeHooks,
|
|
127
|
+
uninstall: code_1.uninstallCodeHooks,
|
|
128
|
+
replaced: [
|
|
129
|
+
...['runInThisContext', 'runInNewContext', 'runInContext', 'compileFunction', 'Script'].map((key) => ({ owner: vm, key })),
|
|
130
|
+
{ owner: globalThis, key: 'Function' },
|
|
131
|
+
],
|
|
132
|
+
added: ['write', 'end'].map((key) => ({ owner: http.ServerResponse.prototype, key })),
|
|
133
|
+
outer: { owner: vm, key: 'runInNewContext' },
|
|
134
|
+
trigger: () => vm.runInNewContext('1 + 2'),
|
|
135
|
+
inputs: [req('1 + 2')],
|
|
136
|
+
detector: { module: detect, name: 'detectCode' },
|
|
137
|
+
attack: 'code_injection',
|
|
138
|
+
});
|
|
139
|
+
// Template engines: stand-ins shaped like each engine's exports (the engines are optional dependencies).
|
|
140
|
+
const templateEngines = [
|
|
141
|
+
['handlebars', ['compile', 'precompile'], '{{name}}'],
|
|
142
|
+
['ejs', ['render', 'compile'], '<%= 1 + 2 %>'],
|
|
143
|
+
['pug', ['compile', 'render', 'compileClient'], '#{1 + 2}'],
|
|
144
|
+
['nunjucks', ['renderString'], '{{ 1 + 2 }}'],
|
|
145
|
+
['lodash', ['template'], '<%= 1 + 2 %>'],
|
|
146
|
+
];
|
|
147
|
+
for (const [engine, keys, source] of templateEngines) {
|
|
148
|
+
const exports = {};
|
|
149
|
+
for (const key of keys) {
|
|
150
|
+
// Named, with an arity, so the kit can see both survive.
|
|
151
|
+
exports[key] = { [key]: function (text, data) { return [text, data]; } }[key];
|
|
152
|
+
}
|
|
153
|
+
(0, hook_kit_1.describeHookContract)({
|
|
154
|
+
name: `template (${engine})`,
|
|
155
|
+
install: () => {
|
|
156
|
+
(0, template_1.patchTemplate)(engine, exports);
|
|
157
|
+
return true;
|
|
158
|
+
},
|
|
159
|
+
uninstall: () => (0, template_1.unpatchTemplate)(exports),
|
|
160
|
+
replaced: keys.map((key) => ({ owner: exports, key })),
|
|
161
|
+
trigger: () => exports[keys[0]](`Hello ${source}`, { name: 'data' }),
|
|
162
|
+
inputs: [req(source)],
|
|
163
|
+
detector: { module: template, name: 'detectTemplate' },
|
|
164
|
+
attack: 'code_injection',
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
// The real Handlebars, when present: the singleton and the compiler module its create() instances call.
|
|
168
|
+
let handlebars;
|
|
169
|
+
let compiler;
|
|
170
|
+
try {
|
|
171
|
+
handlebars = require('handlebars');
|
|
172
|
+
compiler = require('handlebars/dist/cjs/handlebars/compiler/compiler');
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
handlebars = undefined;
|
|
176
|
+
}
|
|
177
|
+
if (handlebars && compiler) {
|
|
178
|
+
const hb = handlebars;
|
|
179
|
+
const internal = compiler;
|
|
180
|
+
(0, hook_kit_1.describeHookContract)({
|
|
181
|
+
name: 'template (real handlebars)',
|
|
182
|
+
install: () => {
|
|
183
|
+
(0, template_1.patchTemplate)('handlebars', hb);
|
|
184
|
+
(0, template_1.patchHandlebarsCompiler)(internal);
|
|
185
|
+
return true;
|
|
186
|
+
},
|
|
187
|
+
uninstall: () => {
|
|
188
|
+
(0, template_1.unpatchTemplate)(hb);
|
|
189
|
+
(0, template_1.unpatchTemplate)(internal);
|
|
190
|
+
},
|
|
191
|
+
replaced: [
|
|
192
|
+
...['compile', 'precompile'].map((key) => ({ owner: hb, key })),
|
|
193
|
+
...['compile', 'precompile'].map((key) => ({ owner: internal, key })),
|
|
194
|
+
],
|
|
195
|
+
trigger: () => hb.compile('Hello {{name}}'),
|
|
196
|
+
inputs: [req('{{name}}')],
|
|
197
|
+
detector: { module: template, name: 'detectTemplate' },
|
|
198
|
+
attack: 'code_injection',
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=hook-contracts.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook-contracts.test.js","sourceRoot":"","sources":["../../../src/rasp/__tests__/hook-contracts.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The checks every RASP sink hook must pass, whoever wrote it. The hooks'
|
|
3
|
+
* own tests cover what each sink detects; this kit covers how a hook sits
|
|
4
|
+
* in the process: install once, restore exactly, keep the replaced
|
|
5
|
+
* functions' shape, check a call once, fail open, stay quiet when RASP is
|
|
6
|
+
* off, and live alongside another wrapper (OpenTelemetry tracing wraps the
|
|
7
|
+
* same functions) in either order.
|
|
8
|
+
*
|
|
9
|
+
* Each hook supplies a harmless trigger: a call its detector flags under
|
|
10
|
+
* the given inputs, safe to run when RASP only reports.
|
|
11
|
+
*/
|
|
12
|
+
import { type RaspContext } from '../context';
|
|
13
|
+
import { type AttackType, type RaspInput } from '../types';
|
|
14
|
+
export type Target = {
|
|
15
|
+
owner: object;
|
|
16
|
+
key: string;
|
|
17
|
+
};
|
|
18
|
+
export type HookSpec = {
|
|
19
|
+
name: string;
|
|
20
|
+
install: () => boolean;
|
|
21
|
+
uninstall: () => void;
|
|
22
|
+
/** Properties the hook replaces. */
|
|
23
|
+
replaced: Target[];
|
|
24
|
+
/** Properties the hook adds (absent before install, removed by uninstall). */
|
|
25
|
+
added?: Target[];
|
|
26
|
+
/** The property the "wrapper on top" check wraps after install (default: the first replaced). */
|
|
27
|
+
outer?: Target;
|
|
28
|
+
/** A harmless call the hook flags under `inputs`. May return, throw or return a promise. */
|
|
29
|
+
trigger: () => unknown;
|
|
30
|
+
inputs: RaspInput[];
|
|
31
|
+
context?: Partial<RaspContext>;
|
|
32
|
+
/** The detector the trigger goes through, to make it fail. */
|
|
33
|
+
detector: {
|
|
34
|
+
module: object;
|
|
35
|
+
name: string;
|
|
36
|
+
};
|
|
37
|
+
attack: AttackType;
|
|
38
|
+
/** Per-test setup and teardown the trigger needs (temp files, a server). */
|
|
39
|
+
beforeEach?: () => unknown;
|
|
40
|
+
afterEach?: () => unknown;
|
|
41
|
+
};
|
|
42
|
+
export declare function describeHookContract(spec: HookSpec): void;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.describeHookContract = describeHookContract;
|
|
4
|
+
/**
|
|
5
|
+
* The checks every RASP sink hook must pass, whoever wrote it. The hooks'
|
|
6
|
+
* own tests cover what each sink detects; this kit covers how a hook sits
|
|
7
|
+
* in the process: install once, restore exactly, keep the replaced
|
|
8
|
+
* functions' shape, check a call once, fail open, stay quiet when RASP is
|
|
9
|
+
* off, and live alongside another wrapper (OpenTelemetry tracing wraps the
|
|
10
|
+
* same functions) in either order.
|
|
11
|
+
*
|
|
12
|
+
* Each hook supplies a harmless trigger: a call its detector flags under
|
|
13
|
+
* the given inputs, safe to run when RASP only reports.
|
|
14
|
+
*/
|
|
15
|
+
const context_1 = require("../context");
|
|
16
|
+
const engine_1 = require("../engine");
|
|
17
|
+
const types_1 = require("../types");
|
|
18
|
+
function describeHookContract(spec) {
|
|
19
|
+
describe(`${spec.name}: hook contract`, () => {
|
|
20
|
+
const events = [];
|
|
21
|
+
const setMode = (mode) => {
|
|
22
|
+
if (mode === 'disabled')
|
|
23
|
+
(0, engine_1.configureEngine)({ enabled: false, applicationName: 'kit', env: {} });
|
|
24
|
+
else
|
|
25
|
+
(0, engine_1.configureEngine)({ enabled: true, applicationName: 'kit', mode, env: {} });
|
|
26
|
+
(0, engine_1.setEventSink)({ add: (e) => events.push(e) });
|
|
27
|
+
};
|
|
28
|
+
const ours = () => events.filter((e) => e.attrs['shield360.rasp.attack'] === spec.attack);
|
|
29
|
+
async function fire() {
|
|
30
|
+
try {
|
|
31
|
+
await (0, context_1.runWithInputs)(spec.inputs, spec.trigger, { inRequest: true, ...spec.context });
|
|
32
|
+
return { blocked: false };
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
return { blocked: error instanceof types_1.RaspBlockedError, error };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const snapshot = (targets) => targets.map((t) => ({ ...t, descriptor: Object.getOwnPropertyDescriptor(t.owner, t.key) }));
|
|
39
|
+
beforeEach(async () => {
|
|
40
|
+
events.length = 0;
|
|
41
|
+
setMode('block');
|
|
42
|
+
await spec.beforeEach?.();
|
|
43
|
+
});
|
|
44
|
+
afterEach(async () => {
|
|
45
|
+
spec.uninstall();
|
|
46
|
+
jest.restoreAllMocks();
|
|
47
|
+
(0, engine_1.setEventSink)(undefined);
|
|
48
|
+
(0, engine_1.configureEngine)({ enabled: false, applicationName: 'default', env: {} });
|
|
49
|
+
await spec.afterEach?.();
|
|
50
|
+
});
|
|
51
|
+
it('installs, and installing again changes nothing', () => {
|
|
52
|
+
expect(spec.install()).toBe(true);
|
|
53
|
+
const first = spec.replaced.map((t) => Reflect.get(t.owner, t.key));
|
|
54
|
+
expect(spec.install()).toBe(true);
|
|
55
|
+
expect(spec.replaced.map((t) => Reflect.get(t.owner, t.key))).toEqual(first);
|
|
56
|
+
});
|
|
57
|
+
it('keeps the name and length of what it replaces', () => {
|
|
58
|
+
const before = snapshot(spec.replaced);
|
|
59
|
+
spec.install();
|
|
60
|
+
for (const { owner, key, descriptor } of before) {
|
|
61
|
+
const now = Reflect.get(owner, key);
|
|
62
|
+
expect(now).not.toBe(descriptor?.value);
|
|
63
|
+
expect(now.name).toBe(descriptor?.value.name);
|
|
64
|
+
expect(now.length).toBe(descriptor?.value.length);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
it('uninstall restores exactly, and twice is harmless', () => {
|
|
68
|
+
const before = snapshot(spec.replaced);
|
|
69
|
+
for (const t of spec.added ?? [])
|
|
70
|
+
expect(Object.prototype.hasOwnProperty.call(t.owner, t.key)).toBe(false);
|
|
71
|
+
spec.install();
|
|
72
|
+
for (const t of spec.added ?? [])
|
|
73
|
+
expect(Object.prototype.hasOwnProperty.call(t.owner, t.key)).toBe(true);
|
|
74
|
+
spec.uninstall();
|
|
75
|
+
spec.uninstall();
|
|
76
|
+
for (const { owner, key, descriptor } of before)
|
|
77
|
+
expect(Object.getOwnPropertyDescriptor(owner, key)).toEqual(descriptor);
|
|
78
|
+
for (const t of spec.added ?? [])
|
|
79
|
+
expect(Object.prototype.hasOwnProperty.call(t.owner, t.key)).toBe(false);
|
|
80
|
+
});
|
|
81
|
+
it('block: the trigger is refused and reported once', async () => {
|
|
82
|
+
spec.install();
|
|
83
|
+
const out = await fire();
|
|
84
|
+
expect(out.blocked).toBe(true);
|
|
85
|
+
expect(ours()).toHaveLength(1);
|
|
86
|
+
expect(ours()[0].attrs['shield360.rasp.decision']).toBe('blocked');
|
|
87
|
+
});
|
|
88
|
+
it('monitor: the trigger goes through and is reported exactly once', async () => {
|
|
89
|
+
setMode('monitor');
|
|
90
|
+
spec.install();
|
|
91
|
+
const out = await fire();
|
|
92
|
+
expect(out.blocked).toBe(false);
|
|
93
|
+
expect(ours()).toHaveLength(1);
|
|
94
|
+
expect(ours()[0].attrs['shield360.rasp.decision']).toBe('monitored');
|
|
95
|
+
});
|
|
96
|
+
it('RASP off: nothing is checked or reported', async () => {
|
|
97
|
+
setMode('disabled');
|
|
98
|
+
const detector = jest.spyOn(spec.detector.module, spec.detector.name);
|
|
99
|
+
spec.install();
|
|
100
|
+
const out = await fire();
|
|
101
|
+
expect(out.blocked).toBe(false);
|
|
102
|
+
expect(detector).not.toHaveBeenCalled();
|
|
103
|
+
expect(events).toHaveLength(0);
|
|
104
|
+
});
|
|
105
|
+
it('fails open when the detector fails', async () => {
|
|
106
|
+
jest.spyOn(spec.detector.module, spec.detector.name).mockImplementation(() => {
|
|
107
|
+
throw new Error('detector unavailable');
|
|
108
|
+
});
|
|
109
|
+
spec.install();
|
|
110
|
+
const out = await fire();
|
|
111
|
+
expect(out.blocked).toBe(false);
|
|
112
|
+
expect(events).toHaveLength(0);
|
|
113
|
+
});
|
|
114
|
+
it('lives alongside a wrapper put on top of it', async () => {
|
|
115
|
+
const target = spec.outer ?? spec.replaced[0];
|
|
116
|
+
spec.install();
|
|
117
|
+
const inner = Reflect.get(target.owner, target.key);
|
|
118
|
+
const descriptor = Object.getOwnPropertyDescriptor(target.owner, target.key);
|
|
119
|
+
// Shaped like a tracing wrapper: a plain function calling what it found.
|
|
120
|
+
const outer = function (...values) {
|
|
121
|
+
return Reflect.apply(inner, this, values);
|
|
122
|
+
};
|
|
123
|
+
Object.defineProperty(target.owner, target.key, { ...descriptor, value: outer });
|
|
124
|
+
try {
|
|
125
|
+
expect((await fire()).blocked).toBe(true);
|
|
126
|
+
spec.uninstall();
|
|
127
|
+
// Uninstall must not tear the outer wrapper off, and what is left must not check.
|
|
128
|
+
expect(Reflect.get(target.owner, target.key)).toBe(outer);
|
|
129
|
+
events.length = 0;
|
|
130
|
+
expect((await fire()).blocked).toBe(false);
|
|
131
|
+
expect(events).toHaveLength(0);
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
Object.defineProperty(target.owner, target.key, descriptor);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=hook-kit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook-kit.js","sourceRoot":"","sources":["../../../src/rasp/__tests__/hook-kit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const http = require("http");
|
|
37
|
+
const https = require("https");
|
|
38
|
+
const dns = require("dns");
|
|
39
|
+
const detect = __importStar(require("../detect"));
|
|
40
|
+
const context_1 = require("../context");
|
|
41
|
+
const engine_1 = require("../engine");
|
|
42
|
+
const types_1 = require("../types");
|
|
43
|
+
const http_1 = require("../hooks/http");
|
|
44
|
+
const index_1 = require("../index");
|
|
45
|
+
let server;
|
|
46
|
+
let url;
|
|
47
|
+
let port;
|
|
48
|
+
let arrivals;
|
|
49
|
+
const tainted = (value, fn) => (0, context_1.runWithInputs)([{ value, key: 'query.q', source: 'request' }], fn, { inRequest: true });
|
|
50
|
+
function configure(mode = 'block', outboundHosts = []) {
|
|
51
|
+
(0, engine_1.configureEngine)({ enabled: true, applicationName: 'a', mode, allow: { outboundHosts }, env: {} });
|
|
52
|
+
}
|
|
53
|
+
function receive(request) {
|
|
54
|
+
return new Promise((resolve, reject) => {
|
|
55
|
+
request.on('error', reject);
|
|
56
|
+
request.on('response', response => {
|
|
57
|
+
response.resume();
|
|
58
|
+
response.on('end', resolve);
|
|
59
|
+
response.on('error', reject);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
beforeEach(async () => {
|
|
64
|
+
configure();
|
|
65
|
+
(0, engine_1.setEventSink)({ add: () => undefined });
|
|
66
|
+
arrivals = jest.fn();
|
|
67
|
+
server = http.createServer((_req, res) => { arrivals(); res.end('fixture'); });
|
|
68
|
+
await new Promise(resolve => server.listen(0, '127.0.0.1', resolve));
|
|
69
|
+
port = server.address().port;
|
|
70
|
+
url = `http://127.0.0.1:${port}/x`;
|
|
71
|
+
});
|
|
72
|
+
afterEach(async () => {
|
|
73
|
+
(0, http_1.uninstallHttpHooks)();
|
|
74
|
+
jest.restoreAllMocks();
|
|
75
|
+
(0, engine_1.configureEngine)({ enabled: false, applicationName: 'a', env: {} });
|
|
76
|
+
(0, engine_1.setEventSink)(undefined);
|
|
77
|
+
server.closeAllConnections();
|
|
78
|
+
await new Promise((resolve, reject) => server.close(error => error ? reject(error) : resolve()));
|
|
79
|
+
});
|
|
80
|
+
for (const [owner, scheme] of [[http, 'http:'], [https, 'https:']]) {
|
|
81
|
+
describe(scheme, () => {
|
|
82
|
+
test.each(['request', 'get'])('%s normalizes every call form', api => {
|
|
83
|
+
const original = jest.spyOn(owner, api).mockImplementation((() => ({})));
|
|
84
|
+
const outbound = jest.spyOn(detect, 'detectOutbound').mockReturnValue(null);
|
|
85
|
+
jest.spyOn(detect, 'detectSsrf').mockReturnValue(null);
|
|
86
|
+
(0, http_1.installHttpHooks)({ alwaysAllowedHosts: [] });
|
|
87
|
+
const endpoint = `${scheme}//127.0.0.1:${port}/x`;
|
|
88
|
+
const callback = () => undefined;
|
|
89
|
+
const forms = [
|
|
90
|
+
[endpoint], [new URL(endpoint)], [endpoint, callback],
|
|
91
|
+
[endpoint, {}, callback], [new URL(endpoint), {}, callback],
|
|
92
|
+
[{ protocol: scheme, hostname: '127.0.0.1', port, path: '/x' }, callback],
|
|
93
|
+
[{ host: '127.0.0.1', port, path: '/x' }],
|
|
94
|
+
];
|
|
95
|
+
for (const values of forms) {
|
|
96
|
+
Reflect.apply(owner[api], owner, values);
|
|
97
|
+
expect(outbound).toHaveBeenLastCalledWith(endpoint, [], []);
|
|
98
|
+
}
|
|
99
|
+
expect(original).toHaveBeenCalledTimes(forms.length);
|
|
100
|
+
expect(outbound).toHaveBeenCalledTimes(forms.length);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
test('tainted literal blocks synchronously before original or server', () => {
|
|
105
|
+
const original = jest.spyOn(http, 'request');
|
|
106
|
+
(0, http_1.installHttpHooks)({ alwaysAllowedHosts: [] });
|
|
107
|
+
expect(() => tainted(url, () => http.request(url))).toThrow(types_1.RaspBlockedError);
|
|
108
|
+
expect(original).not.toHaveBeenCalled();
|
|
109
|
+
expect(arrivals).not.toHaveBeenCalled();
|
|
110
|
+
});
|
|
111
|
+
test('untainted loopback passes and get is checked once', async () => {
|
|
112
|
+
const detector = jest.spyOn(detect, 'detectSsrf');
|
|
113
|
+
(0, http_1.installHttpHooks)({ alwaysAllowedHosts: [] });
|
|
114
|
+
await receive(http.get(url));
|
|
115
|
+
expect(arrivals).toHaveBeenCalledTimes(1);
|
|
116
|
+
expect(detector).toHaveBeenCalledTimes(1);
|
|
117
|
+
});
|
|
118
|
+
test('monitor reports and permits the request', async () => {
|
|
119
|
+
configure('monitor');
|
|
120
|
+
const events = jest.fn();
|
|
121
|
+
(0, engine_1.setEventSink)({ add: events });
|
|
122
|
+
(0, http_1.installHttpHooks)({ alwaysAllowedHosts: [] });
|
|
123
|
+
await receive(tainted(url, () => http.get(url)));
|
|
124
|
+
expect(arrivals).toHaveBeenCalledTimes(1);
|
|
125
|
+
expect(events).toHaveBeenCalledWith(expect.objectContaining({ attrs: expect.objectContaining({
|
|
126
|
+
'shield360.rasp.decision': 'monitored',
|
|
127
|
+
}) }), expect.any(String));
|
|
128
|
+
});
|
|
129
|
+
test('outbound list applies without taint and alwaysAllowedHosts is honored', async () => {
|
|
130
|
+
configure('block', ['allowed.invalid']);
|
|
131
|
+
(0, http_1.installHttpHooks)({ alwaysAllowedHosts: [] });
|
|
132
|
+
expect(() => http.get(url)).toThrow(types_1.RaspBlockedError);
|
|
133
|
+
(0, http_1.uninstallHttpHooks)();
|
|
134
|
+
(0, http_1.installHttpHooks)({ alwaysAllowedHosts: ['127.0.0.1'] });
|
|
135
|
+
await receive(http.get(url));
|
|
136
|
+
expect(arrivals).toHaveBeenCalledTimes(1);
|
|
137
|
+
});
|
|
138
|
+
test.each([false, true])('actual lookup blocks private resolution, all=%s', all => {
|
|
139
|
+
(0, http_1.installHttpHooks)({ alwaysAllowedHosts: [] });
|
|
140
|
+
const hostname = 'fixture.example';
|
|
141
|
+
const endpoint = `http://${hostname}:${port}/x`;
|
|
142
|
+
const lookup = jest.fn((_host, _options, callback) => {
|
|
143
|
+
process.nextTick(() => all ? callback(null, [{ address: '127.0.0.1', family: 4 }]) : callback(null, '127.0.0.1', 4));
|
|
144
|
+
});
|
|
145
|
+
const options = { lookup: lookup, all };
|
|
146
|
+
const request = tainted(endpoint, () => http.get(endpoint, options));
|
|
147
|
+
expect(options.lookup).toBe(lookup);
|
|
148
|
+
return new Promise((resolve, reject) => {
|
|
149
|
+
request.on('response', () => reject(new Error('Unexpected connection')));
|
|
150
|
+
request.on('error', error => {
|
|
151
|
+
try {
|
|
152
|
+
expect(error).toBeInstanceOf(types_1.RaspBlockedError);
|
|
153
|
+
expect(arrivals).not.toHaveBeenCalled();
|
|
154
|
+
resolve();
|
|
155
|
+
}
|
|
156
|
+
catch (failure) {
|
|
157
|
+
reject(failure);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
test('fetch block rejects without calling original', async () => {
|
|
163
|
+
const original = jest.spyOn(globalThis, 'fetch');
|
|
164
|
+
(0, http_1.installHttpHooks)({ alwaysAllowedHosts: [] });
|
|
165
|
+
await expect(tainted(url, () => fetch(url))).rejects.toBeInstanceOf(types_1.RaspBlockedError);
|
|
166
|
+
expect(original).not.toHaveBeenCalled();
|
|
167
|
+
expect(arrivals).not.toHaveBeenCalled();
|
|
168
|
+
});
|
|
169
|
+
describe('an outbound finding in monitor does not hide an SSRF block', () => {
|
|
170
|
+
const settings = () => (0, engine_1.configureEngine)({
|
|
171
|
+
enabled: true, applicationName: 'a', mode: 'block', attacks: { outbound: 'monitor', ssrf: 'block' },
|
|
172
|
+
allow: { outboundHosts: ['api.example.com'] }, env: {},
|
|
173
|
+
});
|
|
174
|
+
test('http.get', () => {
|
|
175
|
+
settings();
|
|
176
|
+
const original = jest.spyOn(http, 'get');
|
|
177
|
+
(0, http_1.installHttpHooks)({ alwaysAllowedHosts: [] });
|
|
178
|
+
expect(() => tainted(url, () => http.get(url))).toThrow(expect.objectContaining({ attack: 'ssrf', rule: 'ssrf.internal' }));
|
|
179
|
+
expect(original).not.toHaveBeenCalled();
|
|
180
|
+
expect(arrivals).not.toHaveBeenCalled();
|
|
181
|
+
});
|
|
182
|
+
test('fetch', async () => {
|
|
183
|
+
settings();
|
|
184
|
+
const original = jest.spyOn(globalThis, 'fetch');
|
|
185
|
+
(0, http_1.installHttpHooks)({ alwaysAllowedHosts: [] });
|
|
186
|
+
await expect(tainted(url, () => fetch(url))).rejects.toMatchObject({ attack: 'ssrf', rule: 'ssrf.internal' });
|
|
187
|
+
expect(original).not.toHaveBeenCalled();
|
|
188
|
+
expect(arrivals).not.toHaveBeenCalled();
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
test('fetch checks DNS addresses before calling original', async () => {
|
|
192
|
+
const original = jest.spyOn(globalThis, 'fetch');
|
|
193
|
+
jest.spyOn(dns.promises, 'lookup').mockImplementation((async () => [{ address: '127.0.0.1', family: 4 }]));
|
|
194
|
+
(0, http_1.installHttpHooks)({ alwaysAllowedHosts: [] });
|
|
195
|
+
const endpoint = `http://fixture.example:${port}/x`;
|
|
196
|
+
await expect(tainted(endpoint, () => fetch(endpoint))).rejects.toBeInstanceOf(types_1.RaspBlockedError);
|
|
197
|
+
expect(original).not.toHaveBeenCalled();
|
|
198
|
+
});
|
|
199
|
+
test('off does not run detection', async () => {
|
|
200
|
+
(0, engine_1.configureEngine)({ enabled: false, applicationName: 'a', env: {} });
|
|
201
|
+
const detector = jest.spyOn(detect, 'detectSsrf');
|
|
202
|
+
(0, http_1.installHttpHooks)({ alwaysAllowedHosts: [] });
|
|
203
|
+
await receive(tainted(url, () => http.get(url)));
|
|
204
|
+
expect(detector).not.toHaveBeenCalled();
|
|
205
|
+
});
|
|
206
|
+
test('detector errors fail open', async () => {
|
|
207
|
+
jest.spyOn(detect, 'detectOutbound').mockImplementation(() => { throw new Error('unavailable'); });
|
|
208
|
+
(0, http_1.installHttpHooks)({ alwaysAllowedHosts: [] });
|
|
209
|
+
await receive(http.get(url));
|
|
210
|
+
expect(arrivals).toHaveBeenCalledTimes(1);
|
|
211
|
+
});
|
|
212
|
+
test('a fetch that cannot be wrapped leaves the http hooks in place', () => {
|
|
213
|
+
const descriptor = Object.getOwnPropertyDescriptor(globalThis, 'fetch');
|
|
214
|
+
const fetchValue = descriptor.value;
|
|
215
|
+
Object.defineProperty(globalThis, 'fetch', { configurable: true, enumerable: descriptor.enumerable, get: () => fetchValue });
|
|
216
|
+
try {
|
|
217
|
+
const original = jest.spyOn(http, 'request');
|
|
218
|
+
expect((0, http_1.installHttpHooks)({ alwaysAllowedHosts: [] })).toBe(true);
|
|
219
|
+
expect(() => tainted(url, () => http.request(url))).toThrow(types_1.RaspBlockedError);
|
|
220
|
+
expect(original).not.toHaveBeenCalled();
|
|
221
|
+
expect(Object.getOwnPropertyDescriptor(globalThis, 'fetch').get).toBeDefined();
|
|
222
|
+
}
|
|
223
|
+
finally {
|
|
224
|
+
(0, http_1.uninstallHttpHooks)();
|
|
225
|
+
Object.defineProperty(globalThis, 'fetch', descriptor);
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
test('alwaysAllowedHosts takes the hosts of the Shield360 URL and the OTLP endpoint', () => {
|
|
229
|
+
expect((0, index_1.alwaysAllowedHosts)(['https://App.Shield360.ai/api', 'http://[::1]:4318/v1/traces', undefined, 'not a url'])).toEqual(['app.shield360.ai', '::1']);
|
|
230
|
+
});
|
|
231
|
+
test('install is idempotent and restores exact descriptors', () => {
|
|
232
|
+
const entries = [http, https].flatMap(owner => ['request', 'get'].map(key => ({ owner, key })));
|
|
233
|
+
const saved = [...entries, { owner: globalThis, key: 'fetch' }].map(entry => ({
|
|
234
|
+
...entry, descriptor: Object.getOwnPropertyDescriptor(entry.owner, entry.key),
|
|
235
|
+
}));
|
|
236
|
+
expect((0, http_1.installHttpHooks)({ alwaysAllowedHosts: [] })).toBe(true);
|
|
237
|
+
const wrapper = http.request;
|
|
238
|
+
expect((0, http_1.installHttpHooks)({ alwaysAllowedHosts: [] })).toBe(true);
|
|
239
|
+
expect(http.request).toBe(wrapper);
|
|
240
|
+
for (const { owner, key, descriptor } of saved) {
|
|
241
|
+
const fn = Reflect.get(owner, key);
|
|
242
|
+
expect(fn.name).toBe(descriptor.value.name);
|
|
243
|
+
expect(fn.length).toBe(descriptor.value.length);
|
|
244
|
+
}
|
|
245
|
+
(0, http_1.uninstallHttpHooks)();
|
|
246
|
+
(0, http_1.uninstallHttpHooks)();
|
|
247
|
+
for (const { owner, key, descriptor } of saved)
|
|
248
|
+
expect(Object.getOwnPropertyDescriptor(owner, key)).toEqual(descriptor);
|
|
249
|
+
});
|
|
250
|
+
//# sourceMappingURL=http-hook.test.js.map
|