Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,8 @@
**Vulnerability:** The static analyzer was missing `yaml.unsafe_load` and `yaml.full_load` in its `_SERIALISATION_SINKS` mapping, potentially leading to false negatives when tracking untrusted data flowing into these dangerous deserialization functions.
**Learning:** Even if functions are listed in rule specifications (like `_SINK_SPECS`), they also need to be properly categorized in the core taint propagation logic (`_SERIALISATION_SINKS`) to ensure the analyzer correctly sheds validation provenance (converting output to `UNKNOWN_RAW`).
**Prevention:** When adding new sinks to rule definitions, always verify if they need to be added to core propagation mappings like `_SERIALISATION_SINKS` or `_PROPAGATING_BUILTINS`.

## 2026-06-28 - Parameter Default Expression Taint Resolution Leak
**Vulnerability:** Untrusted data could leak into `@trusted` functions without triggering `PY-WL-101` because parameter default value expressions were defaulting to the `function_taint` (which is `ASSURED` for trusted functions), masking their true taint in L2 analysis.
**Learning:** Default parameter expressions are evaluated at runtime in the caller's scope when an argument is omitted, not as part of the function body itself. Inheriting the `function_taint` for defaults creates a blind spot where `EXTERNAL_RAW` expressions inside parameter defaults bypass taint checks.
**Prevention:** When evaluating parameter default expressions in static analysis (`_seed_parameters`), always resolve them with a clean base state (`TaintState.INTEGRAL`) rather than inheriting `function_taint` to ensure accurate taint propagation.
8 changes: 4 additions & 4 deletions src/wardline/scanner/taint/variable_level.py
Original file line number Diff line number Diff line change
Expand Up @@ -615,10 +615,10 @@ def _resolve_lambda_body_at_call_inner(
default_taints: dict[str, TaintState] = {}
defaulted_params = positional_params[len(positional_params) - len(args.defaults) :]
for param, default in zip(defaulted_params, args.defaults, strict=True):
default_taints[param.arg] = _resolve_expr(default, function_taint, taint_map, scope)
default_taints[param.arg] = _resolve_expr(default, TaintState.INTEGRAL, taint_map, scope)
for param, kw_default in zip(args.kwonlyargs, args.kw_defaults, strict=True):
if kw_default is not None:
default_taints[param.arg] = _resolve_expr(kw_default, function_taint, taint_map, scope)
default_taints[param.arg] = _resolve_expr(kw_default, TaintState.INTEGRAL, taint_map, scope)

def _omitted_seed(param_name: str) -> TaintState:
default = default_taints.get(param_name)
Expand Down Expand Up @@ -767,12 +767,12 @@ def _seed_parameters(
param_idx = total_pos_args - num_defaults + i
if 0 <= param_idx < len(all_pos_params):
param_name = all_pos_params[param_idx].arg
default_taints[param_name] = _resolve_expr(default_expr, function_taint, taint_map or {}, {})
default_taints[param_name] = _resolve_expr(default_expr, TaintState.INTEGRAL, taint_map or {}, {})

# Map keyword-only parameter defaults
for param, kw_default_expr in zip(args.kwonlyargs, args.kw_defaults, strict=True):
if kw_default_expr is not None:
default_taints[param.arg] = _resolve_expr(kw_default_expr, function_taint, taint_map or {}, {})
default_taints[param.arg] = _resolve_expr(kw_default_expr, TaintState.INTEGRAL, taint_map or {}, {})

def handle_arg(arg: ast.arg) -> None:
fallback = default_taints.get(arg.arg, function_taint)
Expand Down
2 changes: 1 addition & 1 deletion tests/golden/identity/corpus/META.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"corpus_version": 6,
"fingerprint_scheme": "wlfp2",
"reason": "call-site full-span discriminator"
"reason": "Use INTEGRAL for default parameter taint resolution"
}