shieldcortex 4.36.0 → 4.38.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/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/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 +1 -1
- 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 +1 -1
- 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 +1 -1
- 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 +1 -1
- 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 +1 -1
- 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 +1 -1
- 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 +1 -1
- 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 +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/pages/500.html +2 -2
- package/dist/cloud/cli.js +26 -1
- package/dist/defence/firewall/markdown-image-detector.d.ts +15 -0
- package/dist/defence/firewall/markdown-image-detector.js +30 -0
- package/dist/defence/tool-response-enforce.d.ts +57 -0
- package/dist/defence/tool-response-enforce.js +107 -0
- package/dist/defence/tool-response-scanner.d.ts +6 -3
- package/dist/defence/tool-response-scanner.js +56 -6
- package/dist/defence/trust/read-guard.d.ts +45 -0
- package/dist/defence/trust/read-guard.js +76 -0
- package/dist/defence/types.d.ts +9 -0
- package/dist/memory/consolidate.d.ts +2 -1
- package/dist/memory/consolidate.js +7 -2
- package/dist/server.d.ts +6 -0
- package/dist/server.js +77 -11
- package/dist/tools/context.d.ts +2 -0
- package/dist/tools/context.js +15 -4
- package/dist/tools/recall.d.ts +15 -0
- package/dist/tools/recall.js +31 -3
- package/package.json +1 -1
- /package/dashboard/.next/standalone/dashboard/.next/static/{_JsmCyMaqewdhBNXZu1me → PR51g0pS7Wp0zLzu2q6mQ}/_buildManifest.js +0 -0
- /package/dashboard/.next/standalone/dashboard/.next/static/{_JsmCyMaqewdhBNXZu1me → PR51g0pS7Wp0zLzu2q6mQ}/_clientMiddlewareManifest.json +0 -0
- /package/dashboard/.next/standalone/dashboard/.next/static/{_JsmCyMaqewdhBNXZu1me → PR51g0pS7Wp0zLzu2q6mQ}/_ssgManifest.js +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
<!DOCTYPE html><!--
|
|
2
|
-
@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding-right:23px;font-size:24px;font-weight:500;vertical-align:top">500</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:28px">Internal Server Error.</h2></div></div></div><!--$--><!--/$--><script src="/_next/static/chunks/d878b929b21636c4.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[57043,[\"/_next/static/chunks/102f894cc892994d.js\",\"/_next/static/chunks/417032eeb2cd875f.js\"],\"default\"]\n3:I[27657,[\"/_next/static/chunks/102f894cc892994d.js\",\"/_next/static/chunks/417032eeb2cd875f.js\"],\"default\"]\n4:I[56978,[\"/_next/static/chunks/102f894cc892994d.js\",\"/_next/static/chunks/417032eeb2cd875f.js\"],\"OutletBoundary\"]\n5:\"$Sreact.suspense\"\n7:I[56978,[\"/_next/static/chunks/102f894cc892994d.js\",\"/_next/static/chunks/417032eeb2cd875f.js\"],\"ViewportBoundary\"]\n9:I[56978,[\"/_next/static/chunks/102f894cc892994d.js\",\"/_next/static/chunks/417032eeb2cd875f.js\"],\"MetadataBoundary\"]\nb:I[30687,[\"/_next/static/chunks/102f894cc892994d.js\",\"/_next/static/chunks/417032eeb2cd875f.js\"],\"default\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"
|
|
1
|
+
<!DOCTYPE html><!--PR51g0pS7Wp0zLzu2q6mQ--><html id="__next_error__"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/d878b929b21636c4.js"/><script src="/_next/static/chunks/f70f563804550a9c.js" async=""></script><script src="/_next/static/chunks/43d761df92da7cb6.js" async=""></script><script src="/_next/static/chunks/e281719dbabcca1d.js" async=""></script><script src="/_next/static/chunks/9e56d1f8f4d7adcb.js" async=""></script><script src="/_next/static/chunks/turbopack-768a6a8b9db952e0.js" async=""></script><script src="/_next/static/chunks/102f894cc892994d.js" async=""></script><script src="/_next/static/chunks/417032eeb2cd875f.js" async=""></script><meta name="next-size-adjust" content=""/><title>500: Internal Server Error.</title><script src="/_next/static/chunks/a6dad97d9634a72d.js" noModule=""></script></head><body><div hidden=""><!--$--><!--/$--></div><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div style="line-height:48px"><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}
|
|
2
|
+
@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding-right:23px;font-size:24px;font-weight:500;vertical-align:top">500</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:28px">Internal Server Error.</h2></div></div></div><!--$--><!--/$--><script src="/_next/static/chunks/d878b929b21636c4.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[57043,[\"/_next/static/chunks/102f894cc892994d.js\",\"/_next/static/chunks/417032eeb2cd875f.js\"],\"default\"]\n3:I[27657,[\"/_next/static/chunks/102f894cc892994d.js\",\"/_next/static/chunks/417032eeb2cd875f.js\"],\"default\"]\n4:I[56978,[\"/_next/static/chunks/102f894cc892994d.js\",\"/_next/static/chunks/417032eeb2cd875f.js\"],\"OutletBoundary\"]\n5:\"$Sreact.suspense\"\n7:I[56978,[\"/_next/static/chunks/102f894cc892994d.js\",\"/_next/static/chunks/417032eeb2cd875f.js\"],\"ViewportBoundary\"]\n9:I[56978,[\"/_next/static/chunks/102f894cc892994d.js\",\"/_next/static/chunks/417032eeb2cd875f.js\"],\"MetadataBoundary\"]\nb:I[30687,[\"/_next/static/chunks/102f894cc892994d.js\",\"/_next/static/chunks/417032eeb2cd875f.js\"],\"default\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"PR51g0pS7Wp0zLzu2q6mQ\",\"c\":[\"\",\"_global-error\"],\"q\":\"\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"__PAGE__\",{}]}],[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"html\",null,{\"id\":\"__next_error__\",\"children\":[[\"$\",\"head\",null,{\"children\":[\"$\",\"title\",null,{\"children\":\"500: Internal Server Error.\"}]}],[\"$\",\"body\",null,{\"children\":[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"style\":{\"lineHeight\":\"48px\"},\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}\\n@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"paddingRight\":23,\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\"},\"children\":\"500\"}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"28px\"},\"children\":\"Internal Server Error.\"}]}]]}]}]}]]}],[[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/102f894cc892994d.js\",\"async\":true,\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-1\",{\"src\":\"/_next/static/chunks/417032eeb2cd875f.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"$L4\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@6\"}]}]]}],{},null,false,false]},null,false,false],[\"$\",\"$1\",\"h\",{\"children\":[null,[\"$\",\"$L7\",null,{\"children\":\"$L8\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$L9\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.Metadata\",\"children\":\"$La\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$b\",\"$undefined\"],\"S\":true}\n"])</script><script>self.__next_f.push([1,"8:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n"])</script><script>self.__next_f.push([1,"6:null\na:[]\n"])</script></body></html>
|
package/dist/cloud/cli.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getCloudConfig, setCloudConfig, getCloudSyncControls, setCloudSyncControls, getDefenceMode, setDefenceMode, getVerifyConfig, setVerifyConfig, getReviewCopilotConfig, getOpenClawAutoMemory, setOpenClawAutoMemory, isProactiveRecallEnabled, setProactiveRecall, restore410Defaults, getRankerConfig, setRankerConfig, } from './config.js';
|
|
1
|
+
import { getCloudConfig, setCloudConfig, getCloudSyncControls, setCloudSyncControls, getDefenceMode, setDefenceMode, getVerifyConfig, setVerifyConfig, getReviewCopilotConfig, getOpenClawAutoMemory, setOpenClawAutoMemory, isProactiveRecallEnabled, setProactiveRecall, restore410Defaults, getRankerConfig, setRankerConfig, getToolResponseScanConfig, setToolResponseScanConfig, } from './config.js';
|
|
2
2
|
const VALID_RANKER_ENGINES = ['rrf', 'legacy'];
|
|
3
3
|
import { syncAllGraphToCloud } from './graph-sync.js';
|
|
4
4
|
import { syncAllMemoriesToCloud } from './memory-sync.js';
|
|
@@ -17,9 +17,11 @@ export function handleCloudConfig(args) {
|
|
|
17
17
|
const openclawAutoMemory = getOpenClawAutoMemory();
|
|
18
18
|
const ranker = getRankerConfig();
|
|
19
19
|
const syncControls = getCloudSyncControls();
|
|
20
|
+
const toolFirewall = getToolResponseScanConfig();
|
|
20
21
|
const rankerOverridden = !!process.env.SHIELDCORTEX_RANKER;
|
|
21
22
|
console.log('\nShieldCortex Configuration:');
|
|
22
23
|
console.log(` Defence Mode: ${mode}`);
|
|
24
|
+
console.log(` Tool-Output Firewall: ${toolFirewall.scanToolResponses ? toolFirewall.toolResponseMode : 'Off'}`);
|
|
23
25
|
console.log(` Cloud Enabled: ${config.cloudEnabled ? 'Yes' : 'No'}`);
|
|
24
26
|
console.log(` API Key: ${config.cloudApiKey ? config.cloudApiKey.substring(0, 12) + '...' : 'Not set'}`);
|
|
25
27
|
console.log(` Base URL: ${config.cloudBaseUrl}`);
|
|
@@ -188,6 +190,26 @@ export function handleCloudConfig(args) {
|
|
|
188
190
|
console.log(`Proactive recall ${enabled ? 'enabled' : 'disabled'}.`);
|
|
189
191
|
changed = true;
|
|
190
192
|
}
|
|
193
|
+
if (args.includes('--tool-firewall-enforce')) {
|
|
194
|
+
setToolResponseScanConfig({ scanToolResponses: true, toolResponseMode: 'enforce' });
|
|
195
|
+
console.log('Tool-output firewall set to ENFORCE — threatening tool output will be redacted/withheld before the agent sees it.');
|
|
196
|
+
changed = true;
|
|
197
|
+
}
|
|
198
|
+
if (args.includes('--tool-firewall-advisory')) {
|
|
199
|
+
setToolResponseScanConfig({ scanToolResponses: true, toolResponseMode: 'advisory' });
|
|
200
|
+
console.log('Tool-output firewall set to ADVISORY — threats are logged but tool output is delivered intact (default).');
|
|
201
|
+
changed = true;
|
|
202
|
+
}
|
|
203
|
+
if (args.includes('--tool-firewall-off')) {
|
|
204
|
+
setToolResponseScanConfig({ scanToolResponses: false });
|
|
205
|
+
console.log('Tool-output firewall disabled — tool responses are no longer scanned.');
|
|
206
|
+
changed = true;
|
|
207
|
+
}
|
|
208
|
+
if (args.includes('--tool-firewall-on')) {
|
|
209
|
+
setToolResponseScanConfig({ scanToolResponses: true });
|
|
210
|
+
console.log('Tool-output firewall enabled (scanning on).');
|
|
211
|
+
changed = true;
|
|
212
|
+
}
|
|
191
213
|
if (args.includes('--upsell-mute')) {
|
|
192
214
|
setUpsellState({ proMuted: true });
|
|
193
215
|
console.log('Pro upsell muted. Re-enable with --upsell-unmute.');
|
|
@@ -213,6 +235,9 @@ export function handleCloudConfig(args) {
|
|
|
213
235
|
console.log(' --openclaw-auto-memory <true|false> Extract memories from OpenClaw LLM output (default: off)');
|
|
214
236
|
console.log(' --proactive-recall <true|false> Inject SC memory into prompts (default: off — adds latency)');
|
|
215
237
|
console.log(' --ranker <rrf|legacy> Hybrid retrieval engine (default: rrf; SHIELDCORTEX_RANKER env overrides)');
|
|
238
|
+
console.log(' --tool-firewall-enforce Redact/withhold threatening tool output before the agent sees it');
|
|
239
|
+
console.log(' --tool-firewall-advisory Log tool-output threats but deliver intact (default)');
|
|
240
|
+
console.log(' --tool-firewall-off / --tool-firewall-on Disable / enable tool-output scanning');
|
|
216
241
|
console.log(' --restore-4.10-defaults Restore pre-v4.11.0 defaults (recall on, strict interceptor, minimal preamble)');
|
|
217
242
|
console.log(' --upsell-mute Suppress the Pro upsell footer in doctor');
|
|
218
243
|
console.log(' --upsell-unmute Allow the Pro upsell footer to surface again');
|
|
@@ -32,3 +32,18 @@ export interface MarkdownImageExfilResult {
|
|
|
32
32
|
* Scan content for markdown-image exfiltration links.
|
|
33
33
|
*/
|
|
34
34
|
export declare function detectMarkdownImageExfil(content: string): MarkdownImageExfilResult;
|
|
35
|
+
/** Replacement for a neutralised exfil image: a dead host carrying no data. */
|
|
36
|
+
export declare const NEUTRALISED_IMAGE = "";
|
|
37
|
+
/**
|
|
38
|
+
* Strip markdown-image exfiltration links from content for enforce mode.
|
|
39
|
+
*
|
|
40
|
+
* Re-runs the SAME regex + urlLooksLikeExfil predicate as detection and replaces
|
|
41
|
+
* each offending `` match WHOLE (alt dropped too — it can itself carry
|
|
42
|
+
* data). Splices by match offset, so it does not depend on substring equality
|
|
43
|
+
* with a previously-captured (truncated) URL and is unaffected by any other
|
|
44
|
+
* mutation applied to the content first. Benign images are left untouched.
|
|
45
|
+
*/
|
|
46
|
+
export declare function neutraliseMarkdownImageExfil(content: string): {
|
|
47
|
+
content: string;
|
|
48
|
+
stripped: number;
|
|
49
|
+
};
|
|
@@ -81,3 +81,33 @@ export function detectMarkdownImageExfil(content) {
|
|
|
81
81
|
urls,
|
|
82
82
|
};
|
|
83
83
|
}
|
|
84
|
+
/** Replacement for a neutralised exfil image: a dead host carrying no data. */
|
|
85
|
+
export const NEUTRALISED_IMAGE = '';
|
|
86
|
+
/**
|
|
87
|
+
* Strip markdown-image exfiltration links from content for enforce mode.
|
|
88
|
+
*
|
|
89
|
+
* Re-runs the SAME regex + urlLooksLikeExfil predicate as detection and replaces
|
|
90
|
+
* each offending `` match WHOLE (alt dropped too — it can itself carry
|
|
91
|
+
* data). Splices by match offset, so it does not depend on substring equality
|
|
92
|
+
* with a previously-captured (truncated) URL and is unaffected by any other
|
|
93
|
+
* mutation applied to the content first. Benign images are left untouched.
|
|
94
|
+
*/
|
|
95
|
+
export function neutraliseMarkdownImageExfil(content) {
|
|
96
|
+
const spans = [];
|
|
97
|
+
MARKDOWN_IMAGE_PATTERN.lastIndex = 0;
|
|
98
|
+
let match;
|
|
99
|
+
while ((match = MARKDOWN_IMAGE_PATTERN.exec(content)) !== null) {
|
|
100
|
+
if (urlLooksLikeExfil(match[1])) {
|
|
101
|
+
spans.push({ start: match.index, end: match.index + match[0].length });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (spans.length === 0)
|
|
105
|
+
return { content, stripped: 0 };
|
|
106
|
+
// Splice from the end so earlier offsets stay valid.
|
|
107
|
+
let result = content;
|
|
108
|
+
for (let i = spans.length - 1; i >= 0; i--) {
|
|
109
|
+
const { start, end } = spans[i];
|
|
110
|
+
result = result.slice(0, start) + NEUTRALISED_IMAGE + result.slice(end);
|
|
111
|
+
}
|
|
112
|
+
return { content: result, stripped: spans.length };
|
|
113
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool-Response Enforce Layer
|
|
3
|
+
*
|
|
4
|
+
* Advisory mode only LOGS threats in a tool response. Enforce mode must actually
|
|
5
|
+
* change the bytes the agent receives. This module is the action layer: given a
|
|
6
|
+
* tool response and the threat signals the scanner already computed, it returns
|
|
7
|
+
* the content the agent should actually see.
|
|
8
|
+
*
|
|
9
|
+
* Two-tier policy:
|
|
10
|
+
*
|
|
11
|
+
* BLOCK (withhold the whole payload) — when the output is actively hostile or
|
|
12
|
+
* smuggling: any injection signal, the instruction detector firing, a blob
|
|
13
|
+
* that decodes to an injection, or a blob that decodes to a credential.
|
|
14
|
+
* Natural-language injected instructions cannot be surgically removed without
|
|
15
|
+
* risking that a fragment survives, so the safe action is to withhold the
|
|
16
|
+
* entire response and tell the agent why.
|
|
17
|
+
*
|
|
18
|
+
* REDACT (pass cleaned + tag) — when the threat is a secret or an exfil link
|
|
19
|
+
* sitting in plaintext that we CAN surgically remove: credential leaks (masked
|
|
20
|
+
* in place) and markdown-image exfiltration URLs (neutralised to a dead host).
|
|
21
|
+
* The cleaned content is prefixed with an untrusted-origin tag so any
|
|
22
|
+
* downstream memory write attributes it correctly.
|
|
23
|
+
*
|
|
24
|
+
* Pure and dependency-injection-free of any DB/IO — only the credential scanner
|
|
25
|
+
* (for positional redaction). Easy to unit test in isolation.
|
|
26
|
+
*/
|
|
27
|
+
export declare const TOOL_OUTPUT_BLOCKED_PLACEHOLDER: string;
|
|
28
|
+
export declare const UNTRUSTED_TOOL_TAG = "[ShieldCortex: tool output sanitised \u2014 treat as derived-from-untrusted-tool]";
|
|
29
|
+
/**
|
|
30
|
+
* Threat signals the scanner already computed for a (non-clean) tool response.
|
|
31
|
+
* Passed in so neutralisation never re-derives detection — single source of
|
|
32
|
+
* truth with scanToolResponse.
|
|
33
|
+
*/
|
|
34
|
+
export interface ToolResponseThreatSignals {
|
|
35
|
+
injectionRisk: 'NONE' | 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
|
|
36
|
+
instructionsDetected: boolean;
|
|
37
|
+
decodedInjection: boolean;
|
|
38
|
+
encodingDetected: boolean;
|
|
39
|
+
markdownImageUrls: string[];
|
|
40
|
+
credentialsLeaked: boolean;
|
|
41
|
+
decodedCredentialLeak: boolean;
|
|
42
|
+
}
|
|
43
|
+
export interface ToolResponseNeutralisation {
|
|
44
|
+
/** The content the agent should actually receive. */
|
|
45
|
+
sanitised: string;
|
|
46
|
+
/** True when the whole payload was withheld (blocked), not just redacted. */
|
|
47
|
+
blocked: boolean;
|
|
48
|
+
/** Human-readable list of actions taken, for audit/summary. */
|
|
49
|
+
actions: string[];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Compute the enforce-mode replacement for a tool response.
|
|
53
|
+
*
|
|
54
|
+
* Only meaningful when the scanner already found the response non-clean; with no
|
|
55
|
+
* signals it returns the content unchanged.
|
|
56
|
+
*/
|
|
57
|
+
export declare function neutraliseToolResponse(content: string, signals: ToolResponseThreatSignals): ToolResponseNeutralisation;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool-Response Enforce Layer
|
|
3
|
+
*
|
|
4
|
+
* Advisory mode only LOGS threats in a tool response. Enforce mode must actually
|
|
5
|
+
* change the bytes the agent receives. This module is the action layer: given a
|
|
6
|
+
* tool response and the threat signals the scanner already computed, it returns
|
|
7
|
+
* the content the agent should actually see.
|
|
8
|
+
*
|
|
9
|
+
* Two-tier policy:
|
|
10
|
+
*
|
|
11
|
+
* BLOCK (withhold the whole payload) — when the output is actively hostile or
|
|
12
|
+
* smuggling: any injection signal, the instruction detector firing, a blob
|
|
13
|
+
* that decodes to an injection, or a blob that decodes to a credential.
|
|
14
|
+
* Natural-language injected instructions cannot be surgically removed without
|
|
15
|
+
* risking that a fragment survives, so the safe action is to withhold the
|
|
16
|
+
* entire response and tell the agent why.
|
|
17
|
+
*
|
|
18
|
+
* REDACT (pass cleaned + tag) — when the threat is a secret or an exfil link
|
|
19
|
+
* sitting in plaintext that we CAN surgically remove: credential leaks (masked
|
|
20
|
+
* in place) and markdown-image exfiltration URLs (neutralised to a dead host).
|
|
21
|
+
* The cleaned content is prefixed with an untrusted-origin tag so any
|
|
22
|
+
* downstream memory write attributes it correctly.
|
|
23
|
+
*
|
|
24
|
+
* Pure and dependency-injection-free of any DB/IO — only the credential scanner
|
|
25
|
+
* (for positional redaction). Easy to unit test in isolation.
|
|
26
|
+
*/
|
|
27
|
+
import { scanForCredentials } from './credential-leak/index.js';
|
|
28
|
+
import { neutraliseMarkdownImageExfil } from './firewall/markdown-image-detector.js';
|
|
29
|
+
export const TOOL_OUTPUT_BLOCKED_PLACEHOLDER = '[ShieldCortex] Tool output withheld in enforce mode — prompt-injection / data-smuggling detected. ' +
|
|
30
|
+
'The original response was blocked to protect the agent. Review the ShieldCortex audit log for details.';
|
|
31
|
+
export const UNTRUSTED_TOOL_TAG = '[ShieldCortex: tool output sanitised — treat as derived-from-untrusted-tool]';
|
|
32
|
+
function hasAnySignal(s) {
|
|
33
|
+
return (s.injectionRisk !== 'NONE' ||
|
|
34
|
+
s.instructionsDetected ||
|
|
35
|
+
s.decodedInjection ||
|
|
36
|
+
s.encodingDetected ||
|
|
37
|
+
s.markdownImageUrls.length > 0 ||
|
|
38
|
+
s.credentialsLeaked ||
|
|
39
|
+
s.decodedCredentialLeak);
|
|
40
|
+
}
|
|
41
|
+
/** Output is actively hostile / smuggling — withhold the whole payload. */
|
|
42
|
+
function shouldBlock(s) {
|
|
43
|
+
return (s.injectionRisk !== 'NONE' ||
|
|
44
|
+
s.instructionsDetected ||
|
|
45
|
+
s.decodedInjection ||
|
|
46
|
+
s.decodedCredentialLeak);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Compute the enforce-mode replacement for a tool response.
|
|
50
|
+
*
|
|
51
|
+
* Only meaningful when the scanner already found the response non-clean; with no
|
|
52
|
+
* signals it returns the content unchanged.
|
|
53
|
+
*/
|
|
54
|
+
export function neutraliseToolResponse(content, signals) {
|
|
55
|
+
if (!hasAnySignal(signals)) {
|
|
56
|
+
return { sanitised: content, blocked: false, actions: [] };
|
|
57
|
+
}
|
|
58
|
+
if (shouldBlock(signals)) {
|
|
59
|
+
const actions = [];
|
|
60
|
+
if (signals.injectionRisk !== 'NONE') {
|
|
61
|
+
actions.push(`blocked: prompt-injection (${signals.injectionRisk.toLowerCase()})`);
|
|
62
|
+
}
|
|
63
|
+
else if (signals.instructionsDetected) {
|
|
64
|
+
// No high-confidence Iron Dome hit — be honest that this is the heuristic
|
|
65
|
+
// instruction detector, not a graded injection (don't say "injection (none)").
|
|
66
|
+
actions.push('blocked: suspicious-instruction pattern (heuristic)');
|
|
67
|
+
}
|
|
68
|
+
if (signals.decodedInjection)
|
|
69
|
+
actions.push('blocked: encoded payload decoded to injection');
|
|
70
|
+
if (signals.decodedCredentialLeak)
|
|
71
|
+
actions.push('blocked: encoded payload decoded to credential');
|
|
72
|
+
return { sanitised: TOOL_OUTPUT_BLOCKED_PLACEHOLDER, blocked: true, actions };
|
|
73
|
+
}
|
|
74
|
+
// Redact path: surgically clean a payload that merely contains secrets / exfil
|
|
75
|
+
// links in plaintext. The untrusted-origin tag is NOT embedded here — callers
|
|
76
|
+
// convey it out-of-band so redacted structured output (JSON/CSV) stays parseable.
|
|
77
|
+
const actions = [];
|
|
78
|
+
let working = content;
|
|
79
|
+
// Markdown-image exfil FIRST, before any other mutation. Uses a full-match
|
|
80
|
+
// regex over the content (not substring equality with a pre-captured, possibly
|
|
81
|
+
// truncated URL), so credential redaction reordering and >200-char URLs can't
|
|
82
|
+
// defeat it. If the scanner flagged exfil images but none could be located
|
|
83
|
+
// here, fail SAFE: withhold the whole payload rather than deliver it.
|
|
84
|
+
if (signals.markdownImageUrls.length > 0) {
|
|
85
|
+
const { content: stripped, stripped: count } = neutraliseMarkdownImageExfil(working);
|
|
86
|
+
if (count === 0) {
|
|
87
|
+
return {
|
|
88
|
+
sanitised: TOOL_OUTPUT_BLOCKED_PLACEHOLDER,
|
|
89
|
+
blocked: true,
|
|
90
|
+
actions: ['blocked: flagged markdown-image exfil could not be neutralised (fail-safe)'],
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
working = stripped;
|
|
94
|
+
actions.push(`stripped ${count} markdown-image exfil URL(s)`);
|
|
95
|
+
}
|
|
96
|
+
if (signals.credentialsLeaked) {
|
|
97
|
+
const cred = scanForCredentials(working);
|
|
98
|
+
if (cred.leaked && cred.redactedContent) {
|
|
99
|
+
working = cred.redactedContent;
|
|
100
|
+
actions.push(`redacted ${cred.findings.length} credential(s)`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (signals.encodingDetected) {
|
|
104
|
+
actions.push('flagged obfuscated/encoded content (passed through)');
|
|
105
|
+
}
|
|
106
|
+
return { sanitised: working, blocked: false, actions };
|
|
107
|
+
}
|
|
@@ -17,9 +17,12 @@
|
|
|
17
17
|
* It deliberately does NOT pull in the write-path's trust scoring, anomaly,
|
|
18
18
|
* privilege, fragmentation or sensitivity layers — those are write concerns.
|
|
19
19
|
*
|
|
20
|
-
* Advisory by default: logs threats but
|
|
21
|
-
*
|
|
22
|
-
*
|
|
20
|
+
* Advisory by default: logs threats but leaves the response untouched. In
|
|
21
|
+
* enforce mode the scanner additionally computes `sanitisedContent` — the bytes
|
|
22
|
+
* the agent should actually receive (injection withheld, secrets redacted, exfil
|
|
23
|
+
* links stripped) — via the neutraliseToolResponse action layer. Callers
|
|
24
|
+
* (withResponseScan, the scan_tool_response tool) swap in sanitisedContent when
|
|
25
|
+
* present; the scanner never blocks tool EXECUTION, only the threatening output.
|
|
23
26
|
*/
|
|
24
27
|
import type { ToolResponseScanResult } from './types.js';
|
|
25
28
|
/**
|
|
@@ -17,15 +17,19 @@
|
|
|
17
17
|
* It deliberately does NOT pull in the write-path's trust scoring, anomaly,
|
|
18
18
|
* privilege, fragmentation or sensitivity layers — those are write concerns.
|
|
19
19
|
*
|
|
20
|
-
* Advisory by default: logs threats but
|
|
21
|
-
*
|
|
22
|
-
*
|
|
20
|
+
* Advisory by default: logs threats but leaves the response untouched. In
|
|
21
|
+
* enforce mode the scanner additionally computes `sanitisedContent` — the bytes
|
|
22
|
+
* the agent should actually receive (injection withheld, secrets redacted, exfil
|
|
23
|
+
* links stripped) — via the neutraliseToolResponse action layer. Callers
|
|
24
|
+
* (withResponseScan, the scan_tool_response tool) swap in sanitisedContent when
|
|
25
|
+
* present; the scanner never blocks tool EXECUTION, only the threatening output.
|
|
23
26
|
*/
|
|
24
27
|
import { scanForInjection } from './iron-dome/injection-scanner.js';
|
|
25
28
|
import { scanForCredentials } from './credential-leak/index.js';
|
|
26
29
|
import { detectInstructions } from './firewall/instruction-detector.js';
|
|
27
30
|
import { detectEncoding } from './firewall/encoding-detector.js';
|
|
28
31
|
import { detectMarkdownImageExfil } from './firewall/markdown-image-detector.js';
|
|
32
|
+
import { neutraliseToolResponse } from './tool-response-enforce.js';
|
|
29
33
|
import { logAudit } from './audit/logger.js';
|
|
30
34
|
import { isDatabaseInitialized } from '../database/init.js';
|
|
31
35
|
import { getToolResponseScanConfig } from '../cloud/config.js';
|
|
@@ -48,6 +52,11 @@ const HIGH_RISK_TOOLS = new Set([
|
|
|
48
52
|
'export_memories',
|
|
49
53
|
'detect_contradictions',
|
|
50
54
|
]);
|
|
55
|
+
// Instruction-detector pattern groups that are WRITE-path concerns and over-fire
|
|
56
|
+
// on legitimate tool OUTPUT (instructional docs telling the agent which tool to
|
|
57
|
+
// call). Excluded from the read-path instruction signal; real injection groups
|
|
58
|
+
// (system_prompt_marker, hidden_instruction, prompt_extraction, …) still apply.
|
|
59
|
+
const READ_PATH_EXCLUDED_INSTRUCTION_PATTERNS = new Set(['imperative_tool_call']);
|
|
51
60
|
// Tools that only return metadata/stats (not worth scanning)
|
|
52
61
|
const METADATA_ONLY_TOOLS = new Set([
|
|
53
62
|
'memory_stats',
|
|
@@ -90,6 +99,9 @@ export function scanToolResponse(toolName, content, mode) {
|
|
|
90
99
|
summary: `Tool response from "${toolName}" skipped (too short)`,
|
|
91
100
|
durationMs: Math.round(performance.now() - startTime),
|
|
92
101
|
auditId: -1,
|
|
102
|
+
sanitisedContent: null,
|
|
103
|
+
blocked: false,
|
|
104
|
+
enforceActions: [],
|
|
93
105
|
};
|
|
94
106
|
}
|
|
95
107
|
// 1. Injection scan (Iron Dome named patterns — drives the `injection` field
|
|
@@ -97,7 +109,17 @@ export function scanToolResponse(toolName, content, mode) {
|
|
|
97
109
|
const injection = scanForInjection(content);
|
|
98
110
|
// 2. Write-path detectors (parity). detectInstructions folds homoglyphs and
|
|
99
111
|
// scans in windows; detectEncoding decodes base64/hex/url blobs.
|
|
100
|
-
|
|
112
|
+
//
|
|
113
|
+
// FP reduction on the READ path: `imperative_tool_call` ("call the X tool")
|
|
114
|
+
// exists to catch injected directives at WRITE time. On tool OUTPUT it is
|
|
115
|
+
// legitimate instructional content (docs telling the agent which tool to
|
|
116
|
+
// use), so we exclude it here. Real injection phrasing ("ignore previous
|
|
117
|
+
// instructions", "you are now…") lives in the other groups + Iron Dome and
|
|
118
|
+
// is unaffected. Decoded snippets (below) keep full detection — an encoded
|
|
119
|
+
// imperative is inherently suspicious.
|
|
120
|
+
const instructionsRaw = detectInstructions(content);
|
|
121
|
+
const instructionPatterns = instructionsRaw.patterns.filter((p) => !READ_PATH_EXCLUDED_INSTRUCTION_PATTERNS.has(p));
|
|
122
|
+
const instructions = { detected: instructionPatterns.length > 0, patterns: instructionPatterns };
|
|
101
123
|
const encoding = detectEncoding(content);
|
|
102
124
|
// 2b. Decode-and-rescan: re-run instruction + credential detection on each
|
|
103
125
|
// decoded snippet so a BARE base64/hex blob that decodes to an injection
|
|
@@ -155,6 +177,31 @@ export function scanToolResponse(toolName, content, mode) {
|
|
|
155
177
|
!markdownImage.detected &&
|
|
156
178
|
!credentials.leaked;
|
|
157
179
|
const durationMs = Math.round(performance.now() - startTime);
|
|
180
|
+
// 5b. Enforce action layer. Advisory mode only logs; enforce mode computes the
|
|
181
|
+
// content the agent should ACTUALLY receive (block injection, redact
|
|
182
|
+
// secrets, strip exfil links). Single source of truth in
|
|
183
|
+
// neutraliseToolResponse — the scanner just feeds it the signals it found.
|
|
184
|
+
let sanitisedContent = null;
|
|
185
|
+
let blocked = false;
|
|
186
|
+
let enforceActions = [];
|
|
187
|
+
if (!clean && resolvedMode === 'enforce') {
|
|
188
|
+
const neutralisation = neutraliseToolResponse(content, {
|
|
189
|
+
injectionRisk: injection.riskLevel,
|
|
190
|
+
instructionsDetected: instructions.detected,
|
|
191
|
+
decodedInjection,
|
|
192
|
+
encodingDetected: encoding.detected,
|
|
193
|
+
markdownImageUrls: markdownImage.urls,
|
|
194
|
+
credentialsLeaked: credentials.leaked,
|
|
195
|
+
decodedCredentialLeak,
|
|
196
|
+
});
|
|
197
|
+
sanitisedContent = neutralisation.sanitised;
|
|
198
|
+
blocked = neutralisation.blocked;
|
|
199
|
+
enforceActions = neutralisation.actions;
|
|
200
|
+
}
|
|
201
|
+
// Truthful firewall_result: advisory only observes (ALLOW); enforce that
|
|
202
|
+
// withholds the whole payload is a BLOCK; enforce that surgically redacts but
|
|
203
|
+
// still delivers is a QUARANTINE.
|
|
204
|
+
const firewallResult = resolvedMode !== 'enforce' ? 'ALLOW' : blocked ? 'BLOCK' : 'QUARANTINE';
|
|
158
205
|
// 6. Build summary
|
|
159
206
|
let summary;
|
|
160
207
|
if (clean) {
|
|
@@ -202,7 +249,7 @@ export function scanToolResponse(toolName, content, mode) {
|
|
|
202
249
|
source_identifier: toolName,
|
|
203
250
|
trust_score: 0.5,
|
|
204
251
|
sensitivity_level: (credentials.leaked || decodedCredentialLeak) ? 'CONFIDENTIAL' : 'PUBLIC',
|
|
205
|
-
firewall_result:
|
|
252
|
+
firewall_result: firewallResult,
|
|
206
253
|
anomaly_score: anomalyScore,
|
|
207
254
|
threat_indicators: JSON.stringify(threatIndicators),
|
|
208
255
|
blocked_patterns: JSON.stringify(blockedPatterns),
|
|
@@ -219,7 +266,7 @@ export function scanToolResponse(toolName, content, mode) {
|
|
|
219
266
|
persistEvent('defence_event', {
|
|
220
267
|
source_type: 'tool_response',
|
|
221
268
|
source_identifier: toolName,
|
|
222
|
-
firewall_result:
|
|
269
|
+
firewall_result: firewallResult,
|
|
223
270
|
trust_score: 0.5,
|
|
224
271
|
anomaly_score: anomalyScore,
|
|
225
272
|
reason: summary,
|
|
@@ -241,5 +288,8 @@ export function scanToolResponse(toolName, content, mode) {
|
|
|
241
288
|
summary,
|
|
242
289
|
durationMs,
|
|
243
290
|
auditId,
|
|
291
|
+
sanitisedContent,
|
|
292
|
+
blocked,
|
|
293
|
+
enforceActions,
|
|
244
294
|
};
|
|
245
295
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP read-path access guard.
|
|
3
|
+
*
|
|
4
|
+
* The `.mjs` prompt/session hooks already filter recalled rows before injecting
|
|
5
|
+
* them into the prompt. The MCP read TOOLS (`get_memory`, `get_related`,
|
|
6
|
+
* `get_context`, and `recall`) returned rows without applying the access-control
|
|
7
|
+
* engine consistently — so a low-trust / compromised caller could pull RESTRICTED
|
|
8
|
+
* or other-source memories verbatim. This guard closes that path by applying the
|
|
9
|
+
* SAME `checkAccess('read')` tiers the search path uses:
|
|
10
|
+
*
|
|
11
|
+
* - quarantined rows (trustScore === 0) are ALWAYS dropped (pending review);
|
|
12
|
+
* - when a caller source is present, rows the caller cannot read are dropped
|
|
13
|
+
* (RESTRICTED isolation below trust 0.7, own-only below 0.5);
|
|
14
|
+
* - owner / high-trust callers pass through in full (chosen policy — no content
|
|
15
|
+
* redaction on the MCP path; that is the prompt-hook surface's job).
|
|
16
|
+
*
|
|
17
|
+
* No source → only quarantined rows are dropped (callers that don't resolve an
|
|
18
|
+
* identity get no source-relative ACL). In practice the MCP server always
|
|
19
|
+
* resolves a source via resolveToolSource before calling the read tools.
|
|
20
|
+
*/
|
|
21
|
+
import type { DefenceSource } from '../types.js';
|
|
22
|
+
import type { Memory, ContextSummary } from '../../memory/types.js';
|
|
23
|
+
/** Filter recalled memories (camelCase Memory) to those the caller may read. */
|
|
24
|
+
export declare function guardReadMemories(memories: Memory[], source: DefenceSource | undefined): Memory[];
|
|
25
|
+
/**
|
|
26
|
+
* Filter raw snake_case DB rows (e.g. the export path's `SELECT *`) to those the
|
|
27
|
+
* caller may read. Same policy as guardReadMemories, different field casing.
|
|
28
|
+
*/
|
|
29
|
+
export declare function guardReadRows<T extends Record<string, unknown>>(rows: T[], source: DefenceSource | undefined): T[];
|
|
30
|
+
/**
|
|
31
|
+
* Sensitivity-only guard for SHARED-CONTEXT bootstrap surfaces (get_context,
|
|
32
|
+
* start_session, the memory:// resources, restore_context, detect_contradictions).
|
|
33
|
+
*
|
|
34
|
+
* These surfaces feed the prompt / a broadly-shared project summary, so they must
|
|
35
|
+
* NEVER surface RESTRICTED or quarantined rows to ANYONE (matching the .mjs
|
|
36
|
+
* prompt hooks) — but, unlike the per-caller fetch tools, they do NOT apply the
|
|
37
|
+
* source-relative own-only tier, so a low-trust subagent still receives the
|
|
38
|
+
* INTERNAL project context it legitimately needs. Credential isolation without
|
|
39
|
+
* the availability blackout.
|
|
40
|
+
*/
|
|
41
|
+
export declare function guardReadBySensitivity(memories: Memory[]): Memory[];
|
|
42
|
+
/** Apply the sensitivity guard to every memory list in a context summary. */
|
|
43
|
+
export declare function guardContextSummary(summary: ContextSummary): ContextSummary;
|
|
44
|
+
/** Guard a single memory; returns null if the caller may not read it. */
|
|
45
|
+
export declare function guardReadMemory(memory: Memory | null | undefined, source: DefenceSource | undefined): Memory | null;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP read-path access guard.
|
|
3
|
+
*
|
|
4
|
+
* The `.mjs` prompt/session hooks already filter recalled rows before injecting
|
|
5
|
+
* them into the prompt. The MCP read TOOLS (`get_memory`, `get_related`,
|
|
6
|
+
* `get_context`, and `recall`) returned rows without applying the access-control
|
|
7
|
+
* engine consistently — so a low-trust / compromised caller could pull RESTRICTED
|
|
8
|
+
* or other-source memories verbatim. This guard closes that path by applying the
|
|
9
|
+
* SAME `checkAccess('read')` tiers the search path uses:
|
|
10
|
+
*
|
|
11
|
+
* - quarantined rows (trustScore === 0) are ALWAYS dropped (pending review);
|
|
12
|
+
* - when a caller source is present, rows the caller cannot read are dropped
|
|
13
|
+
* (RESTRICTED isolation below trust 0.7, own-only below 0.5);
|
|
14
|
+
* - owner / high-trust callers pass through in full (chosen policy — no content
|
|
15
|
+
* redaction on the MCP path; that is the prompt-hook surface's job).
|
|
16
|
+
*
|
|
17
|
+
* No source → only quarantined rows are dropped (callers that don't resolve an
|
|
18
|
+
* identity get no source-relative ACL). In practice the MCP server always
|
|
19
|
+
* resolves a source via resolveToolSource before calling the read tools.
|
|
20
|
+
*/
|
|
21
|
+
import { checkAccess } from './access-control.js';
|
|
22
|
+
/**
|
|
23
|
+
* Core read decision, shared by the camelCase (Memory) and snake_case (raw row)
|
|
24
|
+
* guards so the policy lives in exactly one place.
|
|
25
|
+
*/
|
|
26
|
+
function callerCanRead(id, storedSource, sensitivityLevel, trustScore, source) {
|
|
27
|
+
// Quarantined memories are never surfaced through a normal read.
|
|
28
|
+
if (trustScore === 0)
|
|
29
|
+
return false;
|
|
30
|
+
// Without a caller identity we cannot make a source-relative decision;
|
|
31
|
+
// surface everything else (the server resolves a source in practice).
|
|
32
|
+
if (!source)
|
|
33
|
+
return true;
|
|
34
|
+
return checkAccess({ id, source: storedSource, sensitivity_level: sensitivityLevel }, source, 'read').canRead;
|
|
35
|
+
}
|
|
36
|
+
/** Filter recalled memories (camelCase Memory) to those the caller may read. */
|
|
37
|
+
export function guardReadMemories(memories, source) {
|
|
38
|
+
return memories.filter((m) => callerCanRead(m.id, m.source, m.sensitivityLevel, m.trustScore, source));
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Filter raw snake_case DB rows (e.g. the export path's `SELECT *`) to those the
|
|
42
|
+
* caller may read. Same policy as guardReadMemories, different field casing.
|
|
43
|
+
*/
|
|
44
|
+
export function guardReadRows(rows, source) {
|
|
45
|
+
return rows.filter((r) => callerCanRead(Number(r.id), r.source ?? null, r.sensitivity_level ?? null, Number(r.trust_score ?? 1), source));
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Sensitivity-only guard for SHARED-CONTEXT bootstrap surfaces (get_context,
|
|
49
|
+
* start_session, the memory:// resources, restore_context, detect_contradictions).
|
|
50
|
+
*
|
|
51
|
+
* These surfaces feed the prompt / a broadly-shared project summary, so they must
|
|
52
|
+
* NEVER surface RESTRICTED or quarantined rows to ANYONE (matching the .mjs
|
|
53
|
+
* prompt hooks) — but, unlike the per-caller fetch tools, they do NOT apply the
|
|
54
|
+
* source-relative own-only tier, so a low-trust subagent still receives the
|
|
55
|
+
* INTERNAL project context it legitimately needs. Credential isolation without
|
|
56
|
+
* the availability blackout.
|
|
57
|
+
*/
|
|
58
|
+
export function guardReadBySensitivity(memories) {
|
|
59
|
+
return memories.filter((m) => m.trustScore !== 0 && m.sensitivityLevel !== 'RESTRICTED');
|
|
60
|
+
}
|
|
61
|
+
/** Apply the sensitivity guard to every memory list in a context summary. */
|
|
62
|
+
export function guardContextSummary(summary) {
|
|
63
|
+
return {
|
|
64
|
+
...summary,
|
|
65
|
+
recentMemories: guardReadBySensitivity(summary.recentMemories),
|
|
66
|
+
keyDecisions: guardReadBySensitivity(summary.keyDecisions),
|
|
67
|
+
activePatterns: guardReadBySensitivity(summary.activePatterns),
|
|
68
|
+
pendingItems: guardReadBySensitivity(summary.pendingItems),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/** Guard a single memory; returns null if the caller may not read it. */
|
|
72
|
+
export function guardReadMemory(memory, source) {
|
|
73
|
+
if (!memory)
|
|
74
|
+
return null;
|
|
75
|
+
return guardReadMemories([memory], source)[0] ?? null;
|
|
76
|
+
}
|
package/dist/defence/types.d.ts
CHANGED
|
@@ -21,6 +21,15 @@ export interface ToolResponseScanResult {
|
|
|
21
21
|
summary: string;
|
|
22
22
|
durationMs: number;
|
|
23
23
|
auditId: number;
|
|
24
|
+
/**
|
|
25
|
+
* Enforce-mode replacement content the agent should actually receive.
|
|
26
|
+
* `null` in advisory mode and whenever the response is clean (nothing to do).
|
|
27
|
+
*/
|
|
28
|
+
sanitisedContent: string | null;
|
|
29
|
+
/** True when enforce mode withheld the whole payload (vs. surgically redacting). */
|
|
30
|
+
blocked: boolean;
|
|
31
|
+
/** Human-readable actions taken in enforce mode (empty otherwise). */
|
|
32
|
+
enforceActions: string[];
|
|
24
33
|
}
|
|
25
34
|
export interface FirewallAnalysis {
|
|
26
35
|
result: FirewallResult;
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* - Cleans up decayed/irrelevant memories
|
|
8
8
|
* - Merges similar memories to reduce redundancy
|
|
9
9
|
*/
|
|
10
|
+
import type { DefenceSource } from '../defence/types.js';
|
|
10
11
|
import { Memory, MemoryConfig, ConsolidationResult, ContextSummary } from './types.js';
|
|
11
12
|
/**
|
|
12
13
|
* Run full consolidation process
|
|
@@ -147,7 +148,7 @@ export declare function getSuggestedContext(currentContext: string, project?: st
|
|
|
147
148
|
/**
|
|
148
149
|
* Export memories as JSON (for backup/transfer)
|
|
149
150
|
*/
|
|
150
|
-
export declare function exportMemories(project?: string): string;
|
|
151
|
+
export declare function exportMemories(project?: string, source?: DefenceSource): string;
|
|
151
152
|
/**
|
|
152
153
|
* Import memories from JSON
|
|
153
154
|
*/
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { getDatabase, withTransaction } from '../database/init.js';
|
|
11
11
|
import { expireQuarantineItems } from '../defence/quarantine/auto-expire.js';
|
|
12
|
+
import { guardReadRows } from '../defence/trust/read-guard.js';
|
|
12
13
|
import { DEFAULT_CONFIG, } from './types.js';
|
|
13
14
|
import { getMemoriesByType, getRecentMemories, promoteMemory, deleteMemory, searchMemories, getMemoryStats, updateDecayScores, addMemory, rowToMemory, } from './store.js';
|
|
14
15
|
import { processDecay, } from './decay.js';
|
|
@@ -794,7 +795,7 @@ export async function getSuggestedContext(currentContext, project, limit = 5) {
|
|
|
794
795
|
/**
|
|
795
796
|
* Export memories as JSON (for backup/transfer)
|
|
796
797
|
*/
|
|
797
|
-
export function exportMemories(project) {
|
|
798
|
+
export function exportMemories(project, source) {
|
|
798
799
|
const db = getDatabase();
|
|
799
800
|
let sql = 'SELECT * FROM memories';
|
|
800
801
|
const params = [];
|
|
@@ -804,7 +805,11 @@ export function exportMemories(project) {
|
|
|
804
805
|
}
|
|
805
806
|
sql += ' ORDER BY created_at ASC';
|
|
806
807
|
const rows = db.prepare(sql).all(...params);
|
|
807
|
-
|
|
808
|
+
// Read ACL: a bulk export is the sharpest exfil vector, so apply the same
|
|
809
|
+
// read guard as the per-tool paths — drop quarantined + rows the caller may
|
|
810
|
+
// not read (RESTRICTED isolation / own-only for low trust). With no caller
|
|
811
|
+
// source, only quarantined rows are dropped.
|
|
812
|
+
return JSON.stringify(guardReadRows(rows, source), null, 2);
|
|
808
813
|
}
|
|
809
814
|
/**
|
|
810
815
|
* Import memories from JSON
|