Problem
When a plugin registers taint sinks via TaintFlowGraph::addSink(), the resulting issue message is hardcoded per taint type in TaintFlowGraph::connectSinksAndSources():
TaintKind::USER_SECRET => new TaintedUserSecret(
'Detected tainted user secret leaking',
// ...
),
There is no way for a plugin to:
- Customize the issue message for a specific sink (e.g. to explain why the sink is dangerous)
- Attach metadata like a CWE identifier
Use Case
In psalm-plugin-laravel#576, we added a handler that detects timing-unsafe comparisons of secrets (CWE-208). The handler adds USER_SECRET | SYSTEM_SECRET taint sinks at ===, ==, strcmp(), and strcasecmp() expressions. When a secret-tainted value flows into one of these, Psalm reports:
TaintedUserSecret: Detected tainted user secret leaking
This is technically correct but misleading — the issue is a timing attack vulnerability, not a secret leak. We'd like to report something like:
TaintedUserSecret: Timing-unsafe comparison of secret — use hash_equals() for constant-time comparison (CWE-208)
Current Workarounds
- Custom taint type → emits
TaintedCustom("Detected tainted <name>"). Slightly better but users can't suppress it independently from other TaintedCustom issues, and there's still no CWE field.
- Direct
PluginIssue emission → allows custom messages but loses taint flow tracking entirely (taint resolution runs after expression analysis).
Suggestion
Allow DataFlowNode (or the sink registration API) to carry an optional message override and/or metadata that gets used when the taint resolution emits the issue. For example:
$sink = DataFlowNode::make($id, $label, $location, null, $taints);
// hypothetical API:
$sink = $sink->withMessage('Timing-unsafe comparison — use hash_equals()');
Or a more structured approach with CWE support on CodeIssue.
Problem
When a plugin registers taint sinks via
TaintFlowGraph::addSink(), the resulting issue message is hardcoded per taint type inTaintFlowGraph::connectSinksAndSources():There is no way for a plugin to:
Use Case
In psalm-plugin-laravel#576, we added a handler that detects timing-unsafe comparisons of secrets (CWE-208). The handler adds
USER_SECRET | SYSTEM_SECRETtaint sinks at===,==,strcmp(), andstrcasecmp()expressions. When a secret-tainted value flows into one of these, Psalm reports:This is technically correct but misleading — the issue is a timing attack vulnerability, not a secret leak. We'd like to report something like:
Current Workarounds
TaintedCustom("Detected tainted <name>"). Slightly better but users can't suppress it independently from otherTaintedCustomissues, and there's still no CWE field.PluginIssueemission → allows custom messages but loses taint flow tracking entirely (taint resolution runs after expression analysis).Suggestion
Allow
DataFlowNode(or the sink registration API) to carry an optional message override and/or metadata that gets used when the taint resolution emits the issue. For example:Or a more structured approach with CWE support on
CodeIssue.