CWE-511: Logic/Time Bomb
Overview
Logic bombs are malicious code that stays inert until a condition is met - a date, a user action, an event - and then causes data deletion, system corruption, or service disruption. Time bombs are the date-triggered variant. Both turn up in insider sabotage and as payloads in compromised dependencies.
Relationship to Other CWEs
CWE-511 is the conditional-trigger case of CWE-506 (Embedded Malicious Code): malicious code that lies dormant until a date, event, or condition fires it, rather than acting immediately. The remediation is CWE-506's, applied to deferred triggers.
OWASP Classification
A08:2025 - Software or Data Integrity Failures
Risk
Critical: Logic bombs enable delayed sabotage: data deleted after a developer leaves, files corrupted, services taken down. They are hard to detect until they trigger, by which point the damage is done.
Remediation Steps
Core Principle: Forbid hidden triggers. Destructive behavior belongs behind transparent, reviewable control flow.
Locate Logic Bombs and Time-Based Triggers
Look for:
- Date or time comparisons gating destructive or unusual behavior
- Delete, drop, or destroy operations behind any condition
- Username or email checks gating unusual behavior
- Execution counts or request thresholds that trigger an action
- Obfuscated code: base64 strings,
eval/exec, encoded conditions - a red flag whatever it turns out to do
Remove Suspicious Conditional-Destructive Code (Primary Defense)
Any code that ties a destructive action to a condition unrelated to its declared business purpose - a hardcoded date, a specific username, an execution counter - has no legitimate reason to exist. Remove it rather than disabling it or commenting it out. If the condition genuinely encodes a business rule, such as a real trial-expiration feature, it should be documented, code-reviewed, and driven by application configuration rather than a hardcoded date buried in unrelated logic.
Use Static Analysis and Mandatory Code Review
Automated pattern detection (semgrep, bandit, FindSecBugs, or an equivalent SAST tool) can flag date comparisons, destructive calls, and obfuscated execution for a human to evaluate. It won't reliably distinguish malicious intent from legitimate code by itself, so pair it with mandatory review by at least one other developer for any change touching destructive operations. A pre-commit or CI check that flags newly introduced date comparisons near delete/drop operations is cheap to add and catches the most common shape of this weakness.
Add Integrity Checks for Critical Modules
Where a module is security-critical (authentication, authorization, payment processing), verify its hash against a known-good manifest before importing or executing it, so tampering is detected before the module runs.
Monitor Destructive Operations at Runtime
Log every destructive operation (deletion, schema changes, service shutdown) with the acting user, timestamp, and call stack, and require confirmation for operations outside normal automated workflows. This doesn't stop a logic bomb from existing in the code, but a triggered one leaves an audit trail, and confirmation gating can catch it before it executes.
Test for Logic Bomb Indicators
- Run the code in an isolated environment (container, VM) with the system clock advanced to future dates and confirm nothing destructive triggers
- Test with different usernames, especially ones resembling former employees or generic admin accounts
- Review all database schema changes and destructive operations for justification
- Check for unexpected cron jobs or scheduled tasks
Common Vulnerable Patterns
These patterns are deliberate rather than accidental, so the question is not how the mistake happened but how the code evades the checks it passed through. Each is shaped to look unremarkable in a diff and to act long after the change was merged, by which point establishing who introduced it and why is much harder.
A date-triggered payload
Why this is vulnerable: the condition is false for the whole of review, testing, staging and the early life of the release, so every form of dynamic verification passes: the tests are not weak, the code genuinely does nothing yet. It also reads like a feature flag or a deprecation cutoff, which are legitimate patterns, so the shape alone is not the tell. What marks it out is the pairing: a date comparison that gates a destructive action, with no ticket, no configuration entry and no other code aware that the date matters.
A usage-count trigger
Why this is vulnerable: the trigger is tied to how much the software is used, so it fires first wherever it is used most - production, and specifically the largest deployment. It cannot be reproduced anywhere else, because a fresh environment starts the counter at zero and would need production-scale traffic to reach the threshold.
A trigger keyed to one identity
// VULNERABLE - user-based logic bomb
if current_user.email == 'ex-employee@company.com':
if action == 'fire':
drop_all_tables()
Why this is vulnerable: the payload is unreachable for everyone except one account, including whoever investigates. Load testing, fuzzing and the entire user base exercise the path without effect. The code is dormant rather than dead: it stays armed for as long as that identity can be presented, which can outlast the person's employment when the account is disabled rather than removed and the check compares a string instead of doing a live lookup.
A trigger that cannot be read
// VULNERABLE - obfuscated trigger, condition hidden from casual review
if evaluate(base64_decode(encoded_condition)):
malicious_action()
Why this is vulnerable: the other three can be argued about - a date check might be a cutoff, a counter might be a sampling rate. This one cannot, because there is no benign reason for a branch condition to be unreadable. Encoding also defeats the search that would otherwise find the others: grepping for the trigger date, the threshold or the email address returns nothing. Treat any predicate that has to be decoded before it can be understood as a finding on that basis alone, before anyone works out what it decodes to.