Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

3 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ›‘οΈ CARE

Canonicalization Β· Attribution Β· Resolution Engine

A shell-specific, static-first pre-execution verifier for shell-executing LLM agents.

ISSRE 2026 Project Page Python License: MIT

Fast like a rule engine. Careful like a judge.

85.64 % F1 Β· 0.91 % FPR Β· 2.32 ms mean latency β€” and only ~4 % of commands ever reach the LLM.


πŸ“’ News

  • [2026-06-16] πŸŽ‰πŸŽ‰ Congratulations! Our paper "CARE: Pre-Execution Command Verification for Shell-Executing LLM Agents" has been accepted at the IEEE International Symposium on Software Reliability Engineering (ISSRE 2026)!
  • [2026-06-16] πŸš€ Project page is live: https://prisma-research.github.io/CARE/

Overview

CARE mediates a candidate shell command before it reaches the host shell. It canonicalizes the command into a stable verification target, derives deterministic multi-view evidence over syntax, command semantics, path context, and provenance-backed risk patterns, and escalates only underdetermined WARN cases to an LLM judge. The common case stays fast, reproducible, and auditable; neural adjudication is reserved for borderline commands.

CARE three-stage pipeline: Canonicalization, Attribution, Resolution

This repository contains the reference implementation of the CARE pipeline as described in the paper "CARE: Pre-Execution Command Verification for Shell-Executing LLM Agents" (ISSRE 2026). It ships only the CARE method β€” no baselines and no experiment harness.

Results at a glance (main split, 549 commands, 12 baselines)

Guard F1 % ↑ DR % ↑ FPR % ↓ Latency ↓
Best static baseline (OpenClaw4Layer) 72.62 57.27 0.30 0.02 ms
Best LLM judge (LLMJudge) 73.09 67.27 11.25 45.9 ms
CARE (w/o Resolution) β€” static only 84.99 75.91 1.82 0.34 ms
CARE β€” full pipeline 85.64 75.91 0.91 2.32 ms

Benign utility is essentially untouched (57.00 % NL2SH resolve rate vs 57.33 % unguarded; 1 deny in 300 tasks), and on 600 Docker-executed, LLM-generated attack commands the static profile cuts realised harm from 74.8 % to 37.3 %.


Pipeline

CARE is a three-stage pipeline (paper Sec. III, Algorithm 1):

                 raw command c
                      β”‚
   Stage 1  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 Canonical- β”‚   N(c) -> Δ‰        β”‚  wrapper unwrap, IFS/var expand,
 ization    β”‚                    β”‚  base64/printf decode, shell -c unwrap
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚ Δ‰
   Stage 2  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 Attributionβ”‚ L1 Structure  Ξ΄_strβ”‚  Eq. 1
            β”‚ L2 Semantic   s_semβ”‚  Eq. 2
            β”‚ L3 Path       s_pthβ”‚  Eq. 3–4
            β”‚ L4 Pattern    s_patβ”‚  Eq. 5   (139 provenance-tagged rules)
            β”‚ L5 Policy β†’ score, β”‚  Eq. 6–7
            β”‚          d_prov     β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚ d_prov ∈ {ALLOW, WARN, DENY}
   Stage 3  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 Resolution β”‚ ALLOW / DENY: finalβ”‚
            β”‚ WARN: skip(c)?     β”‚  Eq. 8–11
            β”‚   yes β†’ DENY       β”‚  (no LLM call)
            β”‚   no  β†’ LLM judge  β”‚  SAFE / DANGEROUS
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β–Ό  final decision d*

Composite score (Eq. 6):

score(c) = w_semΒ·s_sem + w_pathΒ·s_path + w_patΒ·s_pat + w_structΒ·Ξ΄_struct

with the default balanced weights w_sem = w_path = w_pat = 0.30, w_struct = 0.10.

Provisional triage (Eq. 7):

d_prov = ALLOW  if score < Ο„_low
         WARN   if Ο„_low ≀ score < Ο„_high
         DENY   if score β‰₯ Ο„_high

with balanced thresholds Ο„_low = 0.15, Ο„_high = 0.35.

Skip predicates (Eq. 8): a WARN command retains its static DENY and bypasses the LLM when any of

p_rule (Eq. 9)  : a fired L4 rule has MITRE provenance and confidence β‰₯ ΞΈ_rule (0.80)
p_sem  (Eq. 10) : an L2 atom is in a high-risk class with score β‰₯ ΞΈ_sem (0.70)
p_spath(Eq. 11) : the L3 path layer fires (sensitive-location access)

holds. Otherwise the command and its evidence trace go to a single safety-biased LLM judge that returns SAFE/DANGEROUS; any judge error fails closed to DENY.


Repository layout and paper mapping

File Paper concept
care/engine.py β€” CAREEngine Stages 1–2 orchestrator (Algorithm 1)
care/canonicalization.py Stage 1 β€” canonicalization operator N
care/structure.py L1 β€” syntax/structural analysis (Ξ΄_struct, Eq. 1)
care/semantic.py L2 β€” semantic attribution (s_sem, Eq. 2)
care/path.py L3 β€” path-sensitive attribution (s_path, Eq. 3–4)
care/pattern.py L4 β€” pattern & provenance attribution (s_pat, Eq. 5)
care/policy.py L5 β€” weighted aggregation + triage (Eq. 6–7)
care/modes.py L5 β€” strict/balanced/auto operating modes (Appendix A.5)
care/resolution.py β€” CARE Stage 3 β€” skip predicates + LLM judge (Eq. 8–11)
care/common.py shared types + L2 base-score table
care/rules/rule_provenance.json 139-rule bank artifact (Appendix A.4)

Install

git clone https://github.com/prisma-research/CARE.git
cd CARE
pip install -e .            # installs bashlex; add [resolution] for the LLM judge
# or, minimally:
pip install bashlex         # openai only needed for Stage 3

Python β‰₯ 3.9. bashlex is the only core dependency; if it is unavailable the L1 layer degrades to a regex fallback.


Usage

Static engine (deterministic, no network)

from care import CAREEngine

eng = CAREEngine()
r = eng.analyze("rm -rf /var/log/*")
print(r.decision, r.score)          # DENY 0.765
print(r.triggered_layers)           # ['L2_Semantic', 'L3_Path', 'L4_Pattern']
print(r.fired_rules[0]['rule_id'])  # e.g. SE-P-042

analyze() returns an AnalysisResult with the full evidence trace (details['scoring'], per-layer scores, fired rules) so every decision is auditable.

Full pipeline with Resolution (Stage 3)

Stage 3 calls an OpenAI-compatible LLM endpoint on WARN commands that no skip predicate resolves. Point CARE at your server via environment variables:

export CARE_LLM_BASE_URL=http://127.0.0.1:8006/v1
export CARE_LLM_MODEL=Qwen3-Coder-30B-A3B-Instruct
export CARE_LLM_API_KEY=not-needed-local-vllm
from care import CARE

guard = CARE()                       # use_judge=True by default
print(guard.is_dangerous("rsync -avz ./data user@host:/backup/"))

The reported results use Qwen3-Coder-30B-A3B-Instruct served by vLLM, temperature=0, max_tokens=8, single-shot.

Static-only configuration β€” CARE (w/o Resolution)

from care import CARE
guard = CARE(use_judge=False)        # WARN and DENY both enforced as blocked

Operating modes

from care import CAREEngine
strict   = CAREEngine(mode="strict")    # Ο„_low=0.10, Ο„_high=0.20
balanced = CAREEngine(mode="balanced")  # Ο„_low=0.15, Ο„_high=0.35  (default)
auto     = CAREEngine(mode="auto")      # Ο„_low=0.20, Ο„_high=0.50

Rule bank

care/rules/rule_provenance.json contains the 139 provenance-tagged rules used by L4, split by provenance tier (Sec. IV, Appendix A.4):

Tier Count Weight Ο€
MITRE ATT&CK 92 1.00
GTFOBins 31 0.85
Manual Cases 16 0.60
Total 139

Each rule's effective contribution is Ο€(tier) Β· conf(rule); L4 reports the maximum over all fired rules. The JSON artifact is regenerated from the in-code rule specification with python -m care.pattern.


Reproducing the case studies

python examples/quickstart.py
python tests/test_pipeline.py      # or: python -m pytest tests/

The tests assert the paper's constants (139 = 92/31/16 rules; weights 0.3/0.3/0.3/0.1; Ο„_low/Ο„_high; aggregation formula) and the three-way triage on representative commands.


Scope

CARE is a single-command, pre-execution verifier operating on the command string plus bounded path context. It does not observe agent prompts, reasoning, or conversation history, and is a complement to β€” not a replacement for β€” sandboxing and host hardening. Session-level and trajectory-level hazards are out of scope.

Citation

If you use CARE, please cite our ISSRE 2026 paper:

@inproceedings{liu2026care,
  author    = {Liu, Yu and Zhang, Wenxiao and Yang, Zhiwei and Zhang, Zhongyi and
               Feng, Hanqi and Wang, Xinyu and Qiu, Peng and Liu, Yanbing and
               Poczos, Barnabas and Hong, Jin B.},
  title     = {{CARE}: Pre-Execution Command Verification for Shell-Executing {LLM} Agents},
  booktitle = {IEEE International Symposium on Software Reliability Engineering (ISSRE)},
  year      = {2026}
}

License

MIT β€” see LICENSE.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages