Prevent cross-threat mitigation credit in residual risk scoring
- Dominant language
- TypeScript
- Stars
- 155
- Forks
- 37
- Avg merge
- 1d 17h
- Merged PRs (30d)
- 82
Description
## Summary
Residual-risk calculation can grant mitigation credit from one linked threat to an entirely different linked threat that remains exposed.
## Steps to reproduce
1. Create a risk with a high inherent score.
2. Link two threats from different components to that risk.
3. Give Threat A a countermeasure with 100% effectiveness.
4. Leave Threat B with no countermeasures.
5. Recalculate the risk.
Example: Threat A is API Gateway input injection on an AWS WAF component, while Threat B is insufficient logging on an AWS Lambda component.
## Actual behavior
The calculation averages effectiveness across countermeasures found on the linked threats. The uncovered threat contributes no residual exposure, so the risk can receive an almost complete mitigation reduction even though one contributing threat has no control.
For an inherent score of 100, a fully effective control on only Threat A can produce a residual score of approximately 1 while Threat B remains exposed.
## Expected behavior
Controls should receive mitigation credit only for the threat exposure they actually cover. An uncovered contributing threat must continue to influence the aggregate residual risk. The calculation should operate at threat level before aggregating linked threats, according to the project's agreed scoring policy.
The fix does not need to prescribe one universal aggregation formula, but it must prevent a verified control on one component from erasing an unrelated exposed threat.
## Evidence
`compute_residual_score()` iterates over countermeasures globally across the risk's linked threats and averages their effectiveness:
https://github.com/precogly/precogly/blob/cb37379df2bfa9b43b02327e006b4cb6f92e035f/backend/apps/threats/services.py
https://github.com/user-attachments/assets/3dede572-8284-483d-a23e-177d2106122d
Contributor guide
Research direction
Start in backend/apps/threats/services.py at compute_residual_score() and reproduce the linked-threat scenario described in the issue. Trace how countermeasure effectiveness is collected and aggregated across threats. Done means an uncovered linked threat still contributes residual exposure while controls receive credit only for the threat exposure they cover; the issue does not specify a single aggregation formula.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100