Skip to content

taint

taint

Taint tracking — information flow control.

Prevents data leakage through tool chains.

Classes

TaintLabel

Bases: str, Enum

Labels for tainted data.

TaintSet dataclass

TaintSet(labels: FrozenSet[TaintLabel] = frozenset())

Immutable set of taint labels attached to data.

Functions
union
union(other: TaintSet) -> TaintSet

Merge two taint sets.

Source code in src/openjarvis/security/taint.py
def union(self, other: TaintSet) -> TaintSet:
    """Merge two taint sets."""
    return TaintSet(labels=self.labels | other.labels)
has
has(label: TaintLabel) -> bool

Check if a specific label is present.

Source code in src/openjarvis/security/taint.py
def has(self, label: TaintLabel) -> bool:
    """Check if a specific label is present."""
    return label in self.labels
from_labels classmethod
from_labels(*labels: TaintLabel) -> TaintSet

Create from one or more labels.

Source code in src/openjarvis/security/taint.py
@classmethod
def from_labels(cls, *labels: TaintLabel) -> TaintSet:
    """Create from one or more labels."""
    return cls(labels=frozenset(labels))

Functions

check_taint

check_taint(tool_name: str, taint: TaintSet) -> Optional[str]

Check if taint labels violate the sink policy for tool_name.

Returns a violation description string, or None if clean.

Source code in src/openjarvis/security/taint.py
def check_taint(tool_name: str, taint: TaintSet) -> Optional[str]:
    """Check if *taint* labels violate the sink policy for *tool_name*.

    Returns a violation description string, or None if clean.
    """
    forbidden = SINK_POLICY.get(tool_name)
    if forbidden is None:
        return None
    violations = taint.labels & forbidden
    if violations:
        labels_str = ", ".join(
            v.value
            for v in sorted(violations, key=lambda x: x.value)
        )
        return (
            f"Data with labels [{labels_str}] "
            f"cannot be sent to '{tool_name}'."
        )
    return None

declassify

declassify(taint: TaintSet, remove: TaintLabel, reason: str) -> TaintSet

Remove a taint label with an explicit reason (for audit).

The reason is not stored on the TaintSet itself but should be logged externally for accountability.

Source code in src/openjarvis/security/taint.py
def declassify(taint: TaintSet, remove: TaintLabel, reason: str) -> TaintSet:
    """Remove a taint label with an explicit reason (for audit).

    The *reason* is not stored on the TaintSet itself but should be
    logged externally for accountability.
    """
    return TaintSet(labels=taint.labels - {remove})

auto_detect_taint

auto_detect_taint(text: str) -> TaintSet

Auto-detect taint labels in text content.

Uses regex patterns to detect PII and secrets in tool output.

Source code in src/openjarvis/security/taint.py
def auto_detect_taint(text: str) -> TaintSet:
    """Auto-detect taint labels in text content.

    Uses regex patterns to detect PII and secrets in tool output.
    """
    labels: set[TaintLabel] = set()

    for pattern in _PII_PATTERNS:
        if pattern.search(text):
            labels.add(TaintLabel.PII)
            break

    for pattern in _SECRET_PATTERNS:
        if pattern.search(text):
            labels.add(TaintLabel.SECRET)
            break

    return TaintSet(labels=frozenset(labels))

propagate_taint

propagate_taint(input_taint: TaintSet, output_text: str) -> TaintSet

Propagate taint: union of input taint with auto-detected output taint.

Source code in src/openjarvis/security/taint.py
def propagate_taint(
    input_taint: TaintSet,
    output_text: str,
) -> TaintSet:
    """Propagate taint: union of input taint with auto-detected output taint."""
    output_taint = auto_detect_taint(output_text)
    return input_taint.union(output_taint)