Skip to content

close: TUI bypass can be spoofed by any HTTP client #38

@wesm

Description

@wesm

The kata close substance-and-evidence gate (introduced in #32) has an
escape hatch for the TUI: when the close request carries
source: "tui" and reason: "done", the daemon skips
ValidateCloseInput and evidence validation. The intent is that
pressing x in kata tui doesn't force the user to type a 40-char
message and attach typed evidence for an interactive close.

The problem

source is just a string on the JSON request body. Any HTTP client
that can reach the daemon can POST

POST /api/v1/projects/{id}/issues/{ref}/actions/close
{"actor": "agent", "source": "tui", "reason": "done"}

and close the issue with no message and no evidence, bypassing the
anti-abuse policy that the rest of kata close enforces. In the
current no-auth model, the daemon has no trustworthy way to
distinguish a real interactive TUI caller from a forged one.

Options

  1. Transport gate. Refuse source=tui when the connection arrives
    over TCP; honor it only on the local Unix socket. Closes the spoof
    vector against any remote attacker but breaks the keystroke bypass
    for legitimate remote-TUI users (they would have to fall back to
    kata close --done --message ... from the CLI).
  2. Drop the bypass. Require --message and --evidence from every
    close caller, including the TUI. The x key would prompt for a
    one-line message. More friction for humans, no policy hole.
  3. Wait for auth/session identity. Derive "interactive UI session"
    trust from an authenticated principal rather than a self-declared
    JSON field. The proper long-term fix once kata grows real
    authentication.

Interim mitigation

Persist source on the issue.closed event payload so
kata audit closes can flag and filter bypass closes. This isn't a
guard, but it makes abuse visible to reviewers.

Flagged by an automated security review on the PR that introduced the
gate (#32). Deferred from that PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions