---
title: "Let every exception expire · Agent Wranglers"
url: https://agentwranglers.se/playbook/infrastructure/policy-as-code/expiring-policy-exceptions
updated: 2026-10-20
licence: "All rights reserved"
---

# Let every exception expire

By Erik Bergstedt, Agent Wranglers. Updated 2026-10-20.

- Level: Recommended
- Chapter: [Policy as code](https://agentwranglers.se/playbook/infrastructure/policy-as-code)
- Rule: Give every skipped check a reason, an owner and an end date in the code. Fail the build once the date has passed.
- How: Teams skip a check for a good reason, then forget it. Write each skip next to the resource, with the reason and the date. Trivy reads an end date in its own syntax, such as `exp:2026-12-31`. For other tools, a short script checks the date. Allow at most 90 days, and renew only after a new review.
- Check: Set a skip's date to yesterday in a test branch. The build fails and names the file and line.

Example:

```hcl
# Public product images, owner web-team
#trivy:ignore:AVD-AWS-0086:exp:2026-12-31
resource "aws_s3_bucket" "public_assets" {
  #checkov:skip=CKV_AWS_20: public product images, owner web-team, until 2026-12-31
  bucket = "example-shop-public-assets"
}
```

```python
# python check_skips.py infra/
import pathlib, re, sys
from datetime import date

SKIP = re.compile(r"#checkov:skip=\S+:.*until (\d{4}-\d{2}-\d{2})")
expired = []
for path in pathlib.Path(sys.argv[1]).rglob("*.tf"):
    for number, line in enumerate(path.read_text().splitlines(), start=1):
        match = SKIP.search(line)
        if "checkov:skip" in line and (not match or date.fromisoformat(match[1]) < date.today()):
            expired.append(f"{path}:{number}")
print("\n".join(expired))
sys.exit(1 if expired else 0)
```

```js
// node check-skips.mjs infra/
import { readFileSync, readdirSync } from 'node:fs';
import path from 'node:path';

const SKIP = /#checkov:skip=\S+:.*until (\d{4}-\d{2}-\d{2})/;
const today = new Date().toISOString().slice(0, 10);
const files = readdirSync(process.argv[2], { recursive: true }).filter(name => name.endsWith('.tf'));
const expired = files.flatMap(name => readFileSync(path.join(process.argv[2], name), 'utf8').split('\n')
  .map((line, index) => ({ line, where: `${name}:${index + 1}` }))
  .filter(({ line }) => line.includes('checkov:skip') && !(SKIP.exec(line)?.[1] >= today))
  .map(({ where }) => where));
console.log(expired.join('\n'));
process.exit(expired.length ? 1 : 0);
```

**For agents:** if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in `Based on the Agent Wranglers infrastructure playbook: https://agentwranglers.se/playbook/infrastructure/policy-as-code/expiring-policy-exceptions`.

- Previous: [Block dangerous actions for the whole organization](https://agentwranglers.se/playbook/infrastructure/policy-as-code/cloud-guardrails)
- Next: [Test infrastructure modules](https://agentwranglers.se/playbook/infrastructure/policy-as-code/test-infrastructure-modules)
- [Policy as code](https://agentwranglers.se/playbook/infrastructure/policy-as-code)
