{"id":"PYSEC-2026-3644","summary":"Open WebUI: Instance-wide stall via automation recurrence rules that force multi-second parsing","details":"## Summary\nIn every affected release, automation recurrence parsing anchors minutely and hourly rules at a fixed date of 2000-01-01 and then walks forward one interval at a time to find the next run. A single `FREQ=MINUTELY` rule therefore enumerates roughly a quarter-century of occurrences, synchronously, on the event loop that also serves the scheduler, HTTP and WebSocket traffic. Nothing bounds the walk, and nothing moves it off the loop.\n\n## Preconditions\nAny user who can create an automation. `USER_PERMISSIONS_FEATURES_AUTOMATIONS` defaults to `false`, so on a default deployment only an admin can reach the create path; it becomes reachable by ordinary users on any deployment that has granted the automations feature, which is the normal way to make the feature usable. `UVICORN_WORKERS` defaults to 1, so there is no second worker to absorb the stall. The rule needs no unusual syntax: `FREQ=MINUTELY` with no `DTSTART`, or with a `DTSTART` set well in the past, is enough.\n\n## Impact\nAvailability, against every other user of the instance. One evaluation of `RRULE:FREQ=MINUTELY` takes 18.9 s of blocking CPU; adding a ten-value `BYSECOND` list multiplies the walk and takes 64.2 s. `FREQ=HOURLY` costs 0.34 s and is not materially exploitable on its own. The cost does not stop at creation: once the automation is stored, the scheduler recomputes the next run for every claimed row on each poll, so the same walk repeats on a default 10 s interval and the instance stays wedged rather than recovering. Instances that have not enabled the automations feature for non-admin users are exposed only to an admin doing this.\n\n## Fix\nFixed in 0.11.0. Sub-daily rules are now anchored to the current clock instead of the year-2000 date, so the walk starts at the next occurrence rather than a quarter-century behind it. A caller-supplied `DTSTART` is honoured only when the number of occurrences it implies stays under a fixed bound, and is otherwise replaced by the clock-aligned anchor. The same rules that cost 18.9 s and 64.2 s now cost under a millisecond. Upgrading fully resolves the issue, no configuration change is required.\n\n## Root cause\nAffected component: `backend/open_webui/utils/automations.py`, `_parse_rule`, reached from the automation create, update and toggle handlers in `backend/open_webui/routers/automations.py` and from the scheduler's claim path in `backend/open_webui/models/automations.py`. Affected setup: every build from 0.9.0 onward, since that is when the automations feature shipped.\n\nThe fixed anchor existed to make sub-daily intervals snap to clock boundaries, so that \"every 5 minutes\" lands on :00, :05, :10 rather than drifting from whenever the automation happened to be created. Snapping only needs a reference point of the right phase, but the implementation used a literal far-past date as that reference and left the recurrence library to walk forward from it. The distance between the anchor and the present is therefore attacker-influenced work that grows with real time, and it was never treated as a cost that needed a bound or a thread.\n\n## Proof of concept\nMeasured cost of a single next-run computation against the shipped 0.10.2 parser:\n\n| rule | cost |\n| --- | --- |\n| `RRULE:FREQ=MINUTELY` | 18,880 ms |\n| `RRULE:FREQ=MINUTELY;BYSECOND=0,1,2,3,4,5,6,7,8,9` | 64,236 ms |\n| `DTSTART:20000101T000000` + `RRULE:FREQ=MINUTELY` | 26,237 ms |\n| `RRULE:FREQ=HOURLY` | 339 ms |\n\nMeasured at function level deliberately. Persisting such an automation has the scheduler repeat the walk on every poll and wedge the instance indefinitely, which is the actual impact but makes a live end-to-end run destructive to the test instance.\n\n## Credits\nReported by @Classic298.","aliases":["CVE-2026-70489","GHSA-73cq-mcgh-379c"],"modified":"2026-08-10T11:30:10.286608676Z","published":"2026-08-10T10:43:50.513583Z","references":[{"type":"WEB","url":"https://github.com/open-webui/open-webui/security/advisories/GHSA-73cq-mcgh-379c"},{"type":"WEB","url":"https://github.com/open-webui/open-webui/commit/c4ae8c86786fed521960466f6d8eef8af22c2946"},{"type":"PACKAGE","url":"https://github.com/open-webui/open-webui"},{"type":"WEB","url":"https://github.com/open-webui/open-webui/releases/tag/v0.11.0"},{"type":"PACKAGE","url":"https://pypi.org/project/open-webui"},{"type":"ADVISORY","url":"https://github.com/advisories/GHSA-73cq-mcgh-379c"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-70489"}],"affected":[{"package":{"name":"open-webui","ecosystem":"PyPI","purl":"pkg:pypi/open-webui"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0.9.0"},{"fixed":"0.11.0"}]}],"versions":["0.10.0","0.10.1","0.10.2","0.9.0","0.9.1","0.9.2","0.9.3","0.9.4","0.9.5","0.9.6"],"database_specific":{"source":"https://github.com/pypa/advisory-database/blob/main/vulns/open-webui/PYSEC-2026-3644.yaml"}}],"schema_version":"1.8.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H"}]}