---
title: "Refuse updates older than the installed · Agent Wranglers"
url: https://agentwranglers.se/playbook/desktop-apps/update-integrity/no-downgrades
id: DSK-7
level: Recommended
updated: 2026-10-22
tokens: 829
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Refuse updates older than the installed version

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Update integrity](https://agentwranglers.se/playbook/desktop-apps/update-integrity.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-22.

- ID: DSK-7
- Level: Recommended
- Chapter: [Update integrity](https://agentwranglers.se/playbook/desktop-apps/update-integrity.md)
- Rule: The app installs only a version higher than the one it runs, and it reads that version from the signed update data. A downgrade happens only when a person chooses it.
- Check: Serve a validly signed update with a lower version than the installed one. The app does not install it and logs the refusal. A unit test sorts `1.10.0` above `1.9.0`.
- How: An attacker who can replay an old, validly signed update can bring back a hole you already fixed. Put the version inside the signed part of the update, not only in the file name. Compare versions as numbers, part by part, so `1.10.0` sorts above `1.9.0`. To roll back a bad release, ship the old code under a new, higher version number, as [plan to fix forward](https://agentwranglers.se/playbook/mobile-apps/signing-and-release/fix-forward.md) says.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### JavaScript example

```js
const parts = version => version.split('.').map(Number);

export function isNewer(candidate, installed) {
  const [a, b] = [parts(candidate), parts(installed)];
  for (let i = 0; i < Math.max(a.length, b.length); i += 1) {
    if ((a[i] ?? 0) !== (b[i] ?? 0)) return (a[i] ?? 0) > (b[i] ?? 0);
  }
  return false;
}
```

### Python example

```python
def is_newer(candidate: str, installed: str) -> bool:
    as_tuple = lambda version: tuple(int(part) for part in version.split("."))
    return as_tuple(candidate) > as_tuple(installed)
```

## Sources

- [The Update Framework specification](https://theupdateframework.github.io/specification/latest/)

## Related rules

- MOB-12 [Plan to fix forward](https://agentwranglers.se/playbook/mobile-apps/signing-and-release/fix-forward.md) in Mobile apps
- IOT-11 [Refuse firmware older than the installed security version](https://agentwranglers.se/playbook/connected-devices/firmware-updates/anti-rollback.md) in Connected devices

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/desktop-apps/update-integrity/no-downgrades">Agent Wranglers desktop apps, extensions and CLIs playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Verify every update's signature before installing it](https://agentwranglers.se/playbook/desktop-apps/update-integrity/signed-updates.md)
- Next: [Roll out each update in stages with a stop switch](https://agentwranglers.se/playbook/desktop-apps/update-integrity/staged-desktop-updates.md)
- [Update integrity](https://agentwranglers.se/playbook/desktop-apps/update-integrity.md)
