[{"data":1,"prerenderedAt":1033},["ShallowReactive",2],{"navigation_docs":3,"-project-security":270,"-project-security-surround":1028},[4,28,51,110,243],{"title":5,"path":6,"stem":7,"children":8},"Get started","\u002Fget-started","1.get-started",[9,12,16,20,24],{"title":10,"path":6,"stem":11},"Overview","1.get-started\u002Findex",{"title":13,"path":14,"stem":15},"Why Kraft","\u002Fget-started\u002Fwhy-kraft","1.get-started\u002F0.why-kraft",{"title":17,"path":18,"stem":19},"Install","\u002Fget-started\u002Finstall","1.get-started\u002F1.install",{"title":21,"path":22,"stem":23},"Your first work item","\u002Fget-started\u002Ffirst-work-item","1.get-started\u002F2.first-work-item",{"title":25,"path":26,"stem":27},"Troubleshooting and FAQ","\u002Fget-started\u002Ftroubleshooting","1.get-started\u002F3.troubleshooting",{"title":29,"path":30,"stem":31,"children":32},"Concepts","\u002Fconcepts","2.concepts",[33,35,39,43,47],{"title":10,"path":30,"stem":34},"2.concepts\u002Findex",{"title":36,"path":37,"stem":38},"Vocabulary","\u002Fconcepts\u002Fvocabulary","2.concepts\u002F1.vocabulary",{"title":40,"path":41,"stem":42},"How a work item runs","\u002Fconcepts\u002Fhow-a-work-item-runs","2.concepts\u002F2.how-a-work-item-runs",{"title":44,"path":45,"stem":46},"Caps and budgets","\u002Fconcepts\u002Fcaps-and-budgets","2.concepts\u002F3.caps-and-budgets",{"title":48,"path":49,"stem":50},"Why a permission gate","\u002Fconcepts\u002Fpermission-gate","2.concepts\u002F4.permission-gate",{"title":52,"path":53,"stem":54,"children":55},"Guides","\u002Fguides","3.guides",[56,58,62,66,70,74,78,82,86,90,94,98,102,106],{"title":10,"path":53,"stem":57},"3.guides\u002Findex",{"title":59,"path":60,"stem":61},"Use Kraft from your agent","\u002Fguides\u002Fagent-integration","3.guides\u002F01.agent-integration",{"title":63,"path":64,"stem":65},"Kraft Lite","\u002Fguides\u002Fkraft-lite","3.guides\u002F02.kraft-lite",{"title":67,"path":68,"stem":69},"Remote access","\u002Fguides\u002Fremote-access","3.guides\u002F03.remote-access",{"title":71,"path":72,"stem":73},"Add or override a harness","\u002Fguides\u002Fadding-a-harness","3.guides\u002F04.adding-a-harness",{"title":75,"path":76,"stem":77},"Schedule or webhook work","\u002Fguides\u002Fschedule-and-webhook-work","3.guides\u002F05.schedule-and-webhook-work",{"title":79,"path":80,"stem":81},"Add a security review or a gate reviewer","\u002Fguides\u002Fadd-review-agents","3.guides\u002F06.add-review-agents",{"title":83,"path":84,"stem":85},"Kraft for VS Code","\u002Fguides\u002Fvscode","3.guides\u002F07.vscode",{"title":87,"path":88,"stem":89},"Reviewing a change","\u002Fguides\u002Freview-a-change","3.guides\u002F08.review-a-change",{"title":91,"path":92,"stem":93},"Write your own chain","\u002Fguides\u002Fwrite-your-own-chain","3.guides\u002F09.write-your-own-chain",{"title":95,"path":96,"stem":97},"Switch a harness","\u002Fguides\u002Fswitch-harness","3.guides\u002F10.switch-harness",{"title":99,"path":100,"stem":101},"Upgrade your templates","\u002Fguides\u002Fupgrading-templates","3.guides\u002F11.upgrading-templates",{"title":103,"path":104,"stem":105},"Operations","\u002Fguides\u002Foperations","3.guides\u002F12.operations",{"title":107,"path":108,"stem":109},"Worker Kit","\u002Fguides\u002Fworker-kit","3.guides\u002F13.worker-kit",{"title":111,"path":112,"stem":113,"children":114},"Reference","\u002Freference","4.reference",[115,117,139,183,201,205,227,231,235,239],{"title":10,"path":112,"stem":116},"4.reference\u002Findex",{"title":118,"path":119,"stem":120,"children":121},"CLI","\u002Freference\u002Fcli","4.reference\u002F1.cli\u002Findex",[122,123,127,131,135],{"title":10,"path":119,"stem":120},{"title":124,"path":125,"stem":126},"Item verbs","\u002Freference\u002Fcli\u002Fitem","4.reference\u002F1.cli\u002F2.item",{"title":128,"path":129,"stem":130},"View verbs","\u002Freference\u002Fcli\u002Fview","4.reference\u002F1.cli\u002F3.view",{"title":132,"path":133,"stem":134},"Repo verbs","\u002Freference\u002Fcli\u002Frepo","4.reference\u002F1.cli\u002F4.repo",{"title":136,"path":137,"stem":138},"Admin verbs","\u002Freference\u002Fcli\u002Fadmin","4.reference\u002F1.cli\u002F5.admin",{"title":140,"path":141,"stem":142,"children":143},"Configuration","\u002Freference\u002Fconfiguration","4.reference\u002F2.configuration\u002Findex",[144,145,155,159,163,167,171,175,179],{"title":10,"path":141,"stem":142},{"title":146,"path":147,"stem":148,"children":149},"Repos","\u002Freference\u002Fconfiguration\u002Frepos","4.reference\u002F2.configuration\u002F2.repos\u002Findex",[150,151],{"title":10,"path":147,"stem":148},{"title":152,"path":153,"stem":154},"Workspaces","\u002Freference\u002Fconfiguration\u002Frepos\u002Fworkspaces","4.reference\u002F2.configuration\u002F2.repos\u002F3.workspaces",{"title":156,"path":157,"stem":158},"Policy","\u002Freference\u002Fconfiguration\u002Fpolicy","4.reference\u002F2.configuration\u002F3.policy",{"title":160,"path":161,"stem":162},"Library and chains","\u002Freference\u002Fconfiguration\u002Flibrary-and-chains","4.reference\u002F2.configuration\u002F4.library-and-chains",{"title":164,"path":165,"stem":166},"Harnesses file","\u002Freference\u002Fconfiguration\u002Fharnesses-file","4.reference\u002F2.configuration\u002F5.harnesses-file",{"title":168,"path":169,"stem":170},"Access","\u002Freference\u002Fconfiguration\u002Faccess","4.reference\u002F2.configuration\u002F6.access",{"title":172,"path":173,"stem":174},"Intake","\u002Freference\u002Fconfiguration\u002Fintake","4.reference\u002F2.configuration\u002F7.intake",{"title":176,"path":177,"stem":178},"Sandbox host","\u002Freference\u002Fconfiguration\u002Fsandbox","4.reference\u002F2.configuration\u002F8.sandbox",{"title":180,"path":181,"stem":182},"Environment variables","\u002Freference\u002Fconfiguration\u002Fenvironment-variables","4.reference\u002F2.configuration\u002F9.environment-variables",{"title":184,"path":185,"stem":186,"children":187},"Chain nodes","\u002Freference\u002Fchain-nodes","4.reference\u002F3.chain-nodes\u002Findex",[188,189,193,197],{"title":10,"path":185,"stem":186},{"title":190,"path":191,"stem":192},"Subprocess tasks","\u002Freference\u002Fchain-nodes\u002Fsubprocess-tasks","4.reference\u002F3.chain-nodes\u002F2.subprocess-tasks",{"title":194,"path":195,"stem":196},"Fix loop and judge","\u002Freference\u002Fchain-nodes\u002Ffix-loop","4.reference\u002F3.chain-nodes\u002F3.fix-loop",{"title":198,"path":199,"stem":200},"Result file","\u002Freference\u002Fchain-nodes\u002Fresult-file","4.reference\u002F3.chain-nodes\u002F4.result-file",{"title":202,"path":203,"stem":204},"Permission gate","\u002Freference\u002Fpermissions","4.reference\u002F4.permissions",{"title":206,"path":207,"stem":208,"children":209},"Agent harnesses","\u002Freference\u002Fharnesses","4.reference\u002F5.harnesses\u002Findex",[210,211,215,219,223],{"title":10,"path":207,"stem":208},{"title":212,"path":213,"stem":214},"Unattended runs","\u002Freference\u002Fharnesses\u002Funattended-runs","4.reference\u002F5.harnesses\u002F2.unattended-runs",{"title":216,"path":217,"stem":218},"Agent profiles","\u002Freference\u002Fharnesses\u002Fagent-profiles","4.reference\u002F5.harnesses\u002F3.agent-profiles",{"title":220,"path":221,"stem":222},"Harness files","\u002Freference\u002Fharnesses\u002Fharness-files","4.reference\u002F5.harnesses\u002F4.harness-files",{"title":224,"path":225,"stem":226},"Fallback and escalation","\u002Freference\u002Fharnesses\u002Ffallback-and-escalation","4.reference\u002F5.harnesses\u002F5.fallback-and-escalation",{"title":228,"path":229,"stem":230},"Inbound triggers","\u002Freference\u002Ftriggers","4.reference\u002F6.triggers",{"title":232,"path":233,"stem":234},"HTTP API","\u002Freference\u002Fhttp-api","4.reference\u002F7.http-api",{"title":236,"path":237,"stem":238},"MCP tools","\u002Freference\u002Fmcp-tools","4.reference\u002F8.mcp-tools",{"title":240,"path":241,"stem":242},"Events","\u002Freference\u002Fevents","4.reference\u002F9.events",{"title":244,"path":245,"stem":246,"children":247},"Project","\u002Fproject","5.project",[248,250,254,258,262,266],{"title":10,"path":245,"stem":249},"5.project\u002Findex",{"title":251,"path":252,"stem":253},"Architecture","\u002Fproject\u002Farchitecture","5.project\u002F1.architecture",{"title":255,"path":256,"stem":257},"Contributing","\u002Fproject\u002Fcontributing","5.project\u002F2.contributing",{"title":259,"path":260,"stem":261},"Security","\u002Fproject\u002Fsecurity","5.project\u002F3.security",{"title":263,"path":264,"stem":265},"Data and privacy","\u002Fproject\u002Fdata-and-privacy","5.project\u002F4.data-and-privacy",{"title":267,"path":268,"stem":269},"Status and support","\u002Fproject\u002Fstatus-and-support","5.project\u002F5.status-and-support",{"id":271,"title":259,"body":272,"description":1021,"extension":1022,"links":1023,"meta":1024,"navigation":1025,"path":260,"seo":1026,"stem":261,"__hash__":1027},"docs\u002F5.project\u002F3.security.md",{"type":273,"value":274,"toc":1012},"minimark",[275,280,284,479,483,489,667,671,684,705,808,822,826,839,885,889,892,911,929,933,936,996,1000,1008],[276,277,279],"h2",{"id":278},"default-posture","Default posture",[281,282,283],"p",{},"This is what a fresh install does before you change any setting.",[285,286,287,306,340,350,383,393,441,451,465],"ul",{},[288,289,290,294,295,299,300,305],"li",{},[291,292,293],"strong",{},"No sandbox."," No repo sets ",[296,297,298],"code",{},"sandbox:",", so every agent runs directly on\nyour machine, as your user. A sandbox is opt-in per repo; see\n",[301,302,304],"a",{"href":303},"\u002Freference\u002Fconfiguration\u002Frepos#sandboxed-workers","Sandboxed workers",".",[288,307,308,311,312,315,316,319,320,315,323,326,327,330,331,334,335,339],{},[291,309,310],{},"Your home directory and your logins."," A worker's environment is an\nallowlist, but the list includes ",[296,313,314],{},"HOME"," and ",[296,317,318],{},"SSH_AUTH_SOCK",", and it passes\n",[296,321,322],{},"ANTHROPIC_API_KEY",[296,324,325],{},"CLAUDE_CODE_OAUTH_TOKEN"," through. A worker can read\nanything your user can: ",[296,328,329],{},"~\u002F.ssh",", your forge CLI's stored login, your agent's\nlogin, and ",[296,332,333],{},"$KRAFT_HOME",", including the ",[301,336,338],{"href":337},"#the-bearer-token","bearer token",".\nIt can push with your SSH agent.",[288,341,342,345,346,349],{},[291,343,344],{},"Open network."," Without a sandbox and a ",[296,347,348],{},"network:"," policy, a worker can\nreach any host your machine can.",[288,351,352,359,360,363,364,366,367,370,371,374,375,378,379,382],{},[291,353,354,355,358],{},"Claude runs in ",[296,356,357],{},"auto"," with every tool."," Every agent task in the shipped\nchains runs on Claude Code with ",[296,361,362],{},"--permission-mode auto"," and no tool list.\nIn ",[296,365,357],{},", Claude's own classifier decides most calls without asking Kraft.\nA call that does reach Kraft's ",[301,368,369],{"href":203},"permission gate"," is\nallowed, because no ",[296,372,373],{},"allowed_tools"," is set. Only ",[296,376,377],{},"Monitor"," and your\n",[296,380,381],{},"deny_tools"," are refused.",[288,384,385,388,389,392],{},[291,386,387],{},"Gemini and Amp ask nobody."," Gemini runs with ",[296,390,391],{},"--approval-mode yolo"," and\nAmp asks for no approvals, so neither reaches the permission gate. Gemini\ncannot enforce a tool list at all and refuses to launch under one.",[288,394,395,398,399,402,403,406,407,315,410,413,414,417,418,421,422,426,427,429,430,432,433,436,437,440],{},[291,396,397],{},"Escalation turns can force-push their item's branch."," An escalation turn\nis the agent Kraft starts to help with a stopped item. Kraft starts one by\nitself when an item stops for a person somewhere other than a gate\n(",[296,400,401],{},"auto_escalate_stuck",", on by default, up to three times). The turn holds\nthe ",[296,404,405],{},"git-commit",", ",[296,408,409],{},"git-rebase",[296,411,412],{},"git-push"," grants. The push grant covers\nonly a push to the item's own branch, with ",[296,415,416],{},"--force-with-lease"," but not a\nplain ",[296,419,420],{},"--force"," (see ",[301,423,425],{"href":424},"\u002Freference\u002Fpermissions#grants","Grants","), and a grant is\nallowed even under an ",[296,428,373],{}," list; only ",[296,431,381],{}," overrides it.\nA grant does not stop git's own hooks, which the agent can edit. The turn\nruns as a person's session, not a worker's, so it may also retry or resume\nits own item. It cannot approve or reject that item's gates, or raise or\notherwise change its budget or policy: a gate and a spending cap are a\nperson's decision, and the API refuses the escalation's own session. Set\n",[296,434,435],{},"defaults.escalation_grants: []"," in ",[296,438,439],{},"policy.yaml"," to remove the grants.",[288,442,443,446,447,450],{},[291,444,445],{},"The local API has no login."," While Kraft is bound to ",[296,448,449],{},"127.0.0.1",", a\nrequest from this machine needs no password or token. Any local process or\nuser can file, start and approve work through it.",[288,452,453,456,457,460,461,464],{},[291,454,455],{},"An agent deciding its own gates."," A sandboxed worker reaches Kraft only\nthrough its session's channel, which acts as that session and allows only\nreads, progress, thread replies and permission asks on its own item, and an\nescalation turn's retry of it. A worker cannot approve, reject, pause,\nresume, skip, abandon, retry, complete, cancel or escalate its item, revise\nits attachments, overrides, policy or budget, or file work, whatever it sends.\nAn unsandboxed worker runs as your user: it can read Kraft's token, write\nKraft's database and edit its config, so no check inside Kraft can stop it\nfrom approving its own gate or starting work it filed. The ",[296,458,459],{},"kraft"," CLI, the\nMCP server and the API refuse a worker's approve, reject, pause, resume,\nskip, abandon, retry, complete, cancel and escalate on its own item, its\nchanges to that item's attachments, agent and node overrides, policy and budget,\nits review comments and review submissions, and its autostart, when the\nworker identifies itself. That stops an agent following the normal path, not one\nworking around it. If a gate must hold against the agent, run the work in a\n",[301,462,463],{"href":303},"sandbox",", and protect your\ndefault branch with a required review from someone other than the account\nKraft uses.",[288,466,467,470,471,474,475,478],{},[291,468,469],{},"Most shipped gates wait for a person."," The default chain stops for you\nto approve the spec and the plan, before it opens a draft merge request, and\nagain before it marks it ready. Two exceptions: a spec or plan you attach\nat intake arrives already decided, so its gate is dropped; and the\n",[296,472,473],{},"chain_revision_approval"," gate passes on its own when the revision proposes\nno change, which is the usual case. If your forge requires a review, it then\nwaits for that approval before it merges. A gate you give an\n",[296,476,477],{},"auto_review"," task lets that agent's verdict approve it.",[276,480,482],{"id":481},"threat-model","Threat model",[281,484,485,486,488],{},"Kraft runs on your machine, binds ",[296,487,449],{}," by default, and edits your repos\nthrough git worktrees using whatever coding agent you've configured. The\nthings worth being deliberate about:",[285,490,491,505,532,553,575,610,619,637,651],{},[288,492,493,496,497,500,501,504],{},[291,494,495],{},"Loopback by default."," ",[296,498,499],{},"kraft admin start"," refuses to bind a non-loopback\naddress without a password set in ",[296,502,503],{},"access.yaml",". There is no way to expose\nthe API or UI on a LAN or the internet without opting in.",[288,506,507,510,511,514,515,436,518,520,521,523,524,527,528,305],{},[291,508,509],{},"Host allowlist."," A non-loopback bind also checks incoming requests'\n",[296,512,513],{},"Host"," header against ",[296,516,517],{},"allowed_hosts",[296,519,503],{}," — a password alone\ndoes not authorize an arbitrary hostname. See ",[301,522,67],{"href":68},"\nfor the recommended way to reach the board from a phone or another machine\n(bind the machine's Tailscale address). A bare ",[296,525,526],{},"--host 0.0.0.0"," also listens\non your LAN, and a Cloudflare Quick Tunnel is the public internet, guarded\nby the password and a ",[301,529,531],{"href":530},"#login","login throttle",[288,533,534,537,538,541,542,545,546,549,550,305],{},[291,535,536],{},"An agent cannot file work and start it in one step, or approve its own\ngate."," Everything a coding agent files through the MCP tools or\n",[296,539,540],{},"kraft item create"," lands paused; a person starts it, from the board or by\nasking their agent to resume it. ",[296,543,544],{},"kraft item create --autostart"," is a person's shortcut\npast that click, and the server refuses it (403, nothing filed) from a\nKraft worker session or an MCP client. A worker session cannot approve,\nreject, pause, resume, skip, abandon or retry the work item it is itself\nrunning. A sandboxed worker cannot get past either refusal; an unsandboxed\none can. See\n",[301,547,279],{"href":548},"#default-posture"," for why, and\n",[301,551,552],{"href":60},"Agent integration",[288,554,555,558,559,406,562,564,565,568,569,572,573,305],{},[291,556,557],{},"Worker environment is allowlisted, not inherited."," A worker's process\nenvironment is built from a fixed allowlist (",[296,560,561],{},"PATH",[296,563,314],{},", locale, proxy\nand CA vars, ",[296,566,567],{},"KRAFT_*",", the agent's credential var) plus whatever a repo's\n",[296,570,571],{},"repos.yaml"," entry explicitly declares — not whatever the Kraft daemon's own\nshell happened to have set. See ",[301,574,140],{"href":147},[288,576,577,580,581,584,585,588,589,593,594,596,597,601,602,605,606,305],{},[291,578,579],{},"A sandbox bounds what a worker writes, and with a network policy what it\nreaches."," A sandboxed worker cannot move a branch in your repository other\nthan its own, and its tool policy is enforced in the container or the launch\nis refused. Git state it plants in its worktree, such as a HEAD naming another\nbranch or a rebase or merge in progress, stops the item for you; Kraft never\ncommits, rebases or aborts over it. Without a ",[296,582,583],{},"network"," policy its network\nis not restricted, and on\na cloud VM the metadata address is reachable; ",[296,586,587],{},"kraft admin doctor"," warns\nabout it. With one, the worker has only loopback and reaches out only\nthrough Kraft's own proxy, on a channel that is its session's alone. Only\nthe hosts the policy allows are reachable, and loopback, link-local, cloud\nmetadata and the host's own addresses never are. Refusals are recorded.\nOn Docker Desktop and Podman machine the channel is a mutual-TLS\nconnection to the daemon's loopback, identified by a certificate from\nKraft's own CA that only that session's second relay holds, never the\nworker; it expires after seven days, and a longer session fails closed.\nThe limit: the allow list\nis enforced on the requested name and the dialled address, so an allowed\nname on a shared CDN address can reach other names that address serves\n(domain fronting). Through an upstream proxy, the upstream resolves the\nname again, so the checked address is not necessarily the one reached. See ",[301,590,592],{"href":591},"\u002Freference\u002Fconfiguration\u002Frepos#network-policy","Network policy",".\nThe same channel is the worker's only route to Kraft: a ",[296,595,459],{}," call from\ninside acts as that session, whatever it sends, and only on its own work\nitem; anything else is refused and recorded. A permission hook that gets\nno answer denies. See ",[301,598,600],{"href":599},"\u002Freference\u002Fconfiguration\u002Frepos#callbacks-from-a-sandbox","Callbacks from a sandbox",".\nA variable a repository lists under ",[296,603,604],{},"credentials"," never enters the\ncontainer: it holds a sentinel, and the proxy, holding the real value in\nmemory, terminates TLS for that credential's host alone (with a\ncertificate from Kraft's CA, which such a container trusts), verifies the\nreal host against the daemon's own roots, and replaces the sentinel in\nthe declared header, refusing any request that does not carry it. The\nlimits: HTTP\u002F1.1 only, no upgrade to a managed host, and a host that\nechoed the key in its response would hand it to the worker. See\n",[301,607,609],{"href":608},"\u002Freference\u002Fconfiguration\u002Frepos#credentials","Credentials",[288,611,612,615,616,305],{},[291,613,614],{},"A sandbox covers a workspace's members as it covers the root."," Each\nmember is checked out from its connected repository, never from a git\ndirectory the worker can write, and the files host git trusts for it are\nread-only in the container. A member Kraft did not check out, or one a\nworker swapped, stops the item before host git runs in it. See\n",[301,617,152],{"href":618},"\u002Freference\u002Fconfiguration\u002Frepos\u002Fworkspaces#sandboxing",[288,620,621,624,625,628,629,632,633,305],{},[291,622,623],{},"A Kit runs only what Kraft enforces."," A ",[296,626,627],{},"kind: kit"," sandbox runs a Kit\npinned by digest whose descriptor decodes strictly, lowered onto the same\nDocker sandbox: its network lists, credentials and limits alone, with no\nharness host added. A required capability Kraft does not enforce stops\nthe item naming it before anything runs, and an optional one is skipped\nand recorded. A Kit credential's value comes only from the daemon\nvariable ",[296,630,631],{},"sandbox.yaml"," binds to its service, never from a variable the\nKit names. Kraft runs operator-authored Kits; Docker's published ones are\nrefused. See ",[301,634,636],{"href":635},"\u002Freference\u002Fconfiguration\u002Frepos#kits","Kits",[288,638,639,642,643,646,647,650],{},[291,640,641],{},"Settings can change what the daemon runs."," A harness profile's\n",[296,644,645],{},"executable"," (Settings → Harnesses) is the program every agent launch on\nthat profile starts, and a repository's ",[296,648,649],{},"setup_command"," (Settings → Repos)\nruns in every new worktree. Both are editable by anyone who can open\nSettings, so the Settings password guards command execution on this\nmachine, not only configuration. Keep the bind on loopback or behind the\naccess password, and review these fields after anyone else has had access.",[288,652,653,659,660,305],{},[291,654,655,658],{},[296,656,657],{},"install.sh"," is a shell script fetched and piped from the internet."," It\nis short by design — read it before you run it:\n",[301,661,665],{"href":662,"rel":663},"https:\u002F\u002Fgithub.com\u002FitsOmidKarami\u002Fkraft\u002Fblob\u002Fmain\u002Finstall.sh",[664],"nofollow",[296,666,657],{},[276,668,670],{"id":669},"the-bearer-token","The bearer token",[281,672,673,676,677,680,681,305],{},[296,674,675],{},"$KRAFT_HOME\u002Frun\u002Fmcp-token"," is a full-admin credential. A request that\ncarries it as ",[296,678,679],{},"Authorization: Bearer \u003Ctoken>"," passes the login check on every\nroute: it can file, start, approve and cancel work, and change settings. It is\nnot limited to ",[296,682,683],{},"\u002Fapi\u002Ftriggers",[281,685,686,689,690,693,694,697,698,701,702,704],{},[296,687,688],{},"$KRAFT_HOME\u002Frun\u002Ftrigger-token"," is the one to hand out. It passes the login\ncheck on ",[296,691,692],{},"POST \u002Fapi\u002Ftriggers"," only, so its holder can file work, which lands\npaused, and nothing else. On any other route Kraft treats it as no credential\nand answers ",[296,695,696],{},"401",". The ",[296,699,700],{},"mcp-token"," works on ",[296,703,692],{}," too.",[285,706,707,725,731],{},[288,708,709,710,713,714,716,717,720,721,724],{},"Kraft creates both files with mode ",[296,711,712],{},"0600"," on first start and keeps them after\nthat. ",[296,715,587],{}," fails its ",[296,718,719],{},"mcp token"," or ",[296,722,723],{},"trigger token"," check if\nthe file's mode gives anyone but you any access.",[288,726,727,728,730],{},"The ",[296,729,459],{}," CLI and the MCP server read the file on every call, so they\nneed no setup.",[288,732,733,734],{},"To rotate either, stop the server, delete the file and start again. Kraft\nwrites a new token on start. Then update any copy you put elsewhere, such as\na CI secret.",[735,736,741],"pre",{"className":737,"code":738,"language":739,"meta":740,"style":740},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","kraft admin stop\nrm \"${KRAFT_HOME:-$HOME\u002F.kraft}\u002Frun\u002Ftrigger-token\"   # or run\u002Fmcp-token\nkraft admin start\n","bash","",[296,742,743,758,798],{"__ignoreMap":740},[744,745,748,751,755],"span",{"class":746,"line":747},"line",1,[744,749,459],{"class":750},"sBMFI",[744,752,754],{"class":753},"sfazB"," admin",[744,756,757],{"class":753}," stop\n",[744,759,761,764,768,772,775,778,781,783,785,788,791,794],{"class":746,"line":760},2,[744,762,763],{"class":750},"rm",[744,765,767],{"class":766},"sMK4o"," \"${",[744,769,771],{"class":770},"sTEyZ","KRAFT_HOME",[744,773,774],{"class":766},":-",[744,776,777],{"class":770},"$HOME",[744,779,780],{"class":766},"\u002F",[744,782,305],{"class":753},[744,784,459],{"class":770},[744,786,787],{"class":766},"}",[744,789,790],{"class":753},"\u002Frun\u002Ftrigger-token",[744,792,793],{"class":766},"\"",[744,795,797],{"class":796},"sHwdD","   # or run\u002Fmcp-token\n",[744,799,801,803,805],{"class":746,"line":800},3,[744,802,459],{"class":750},[744,804,754],{"class":753},[744,806,807],{"class":753}," start\n",[809,810,811,812,815,816,818,819,821],"warning",{},"Give CI systems and webhook senders the ",[296,813,814],{},"trigger-token",", never the\n",[296,817,700],{},". Anyone with the ",[296,820,700],{}," has full control of this Kraft\ninstance and of the work it runs in your repos.",[276,823,825],{"id":824},"login","Login",[281,827,828,829,831,832,406,835,838],{},"Remote access uses a password, stored in ",[296,830,503],{}," as a salted scrypt\nhash. A successful login sets an ",[296,833,834],{},"HttpOnly",[296,836,837],{},"SameSite=Lax"," session cookie.",[285,840,841,855,868],{},[288,842,843,846,847,850,851,854],{},[291,844,845],{},"Failed logins are throttled per client address."," After 5 wrong passwords\nfrom one address within 15 minutes, Kraft answers that address ",[296,848,849],{},"429"," with a\n",[296,852,853],{},"Retry-After"," header, even for the right password, until 15 minutes have\npassed since the last failure. A successful login clears the count. The\ncounts live in memory, so a restart clears them too.",[288,856,857,860,861,864,865,867],{},[291,858,859],{},"The address is the one Kraft sees."," A proxy or tunnel on the same machine\ncan name the real client in ",[296,862,863],{},"X-Forwarded-For","; Kraft believes that header\nonly from ",[296,866,449],{},", so a remote caller cannot pick its own address. A\ntunnel that sends no such header makes every visitor look like the same\naddress, and then the throttle is global: 5 wrong guesses from anyone lock\neveryone out for 15 minutes. That still guards the password, but use a long\nrandom one before you expose the board anywhere.",[288,869,870,877,878,881,882,884],{},[291,871,872,873,876],{},"The cookie is ",[296,874,875],{},"Secure"," over HTTPS."," When the login request arrives over\nHTTPS, or carries the ",[296,879,880],{},"X-Forwarded-Proto: https"," a tunnel sets, the cookie is\nmarked ",[296,883,875],{}," and the browser never sends it over plain HTTP. A login over\nplain HTTP, such as loopback or Tailscale, gets a cookie without it.",[276,886,888],{"id":887},"prompt-injection","Prompt injection",[281,890,891],{},"Everything a worker reads is input to the agent, and text in it can steer\nthe agent. That includes:",[285,893,894,897,908],{},[288,895,896],{},"the repository's files, including ones other people wrote;",[288,898,899,900,903,904,907],{},"a work item's title and description, whether a person typed it, a\n",[301,901,902],{"href":229},"trigger"," posted it or\n",[301,905,906],{"href":173},"auto-intake"," copied it from a bead;",[288,909,910],{},"review comments on the merge request, which the feedback loop asks the\nagent to address.",[281,912,913,914,916,917,919,920,406,922,924,925,928],{},"Kraft does not filter or sanitize any of it. What limits the damage is what\nlimits any other agent mistake: a\n",[301,915,463],{"href":303}," with a ",[296,918,348],{},"\npolicy, a tool policy (",[296,921,373],{},[296,923,381],{},"), and the gates, where a\nperson reads the change before it merges. Under the\n",[301,926,927],{"href":548},"default posture",", an injected instruction runs with your\nuser's access. Without a sandbox, do not point Kraft at a repository, a\ntrigger source or a bead queue whose content you do not trust.",[276,930,932],{"id":931},"out-of-scope","Out of scope",[281,934,935],{},"Kraft does not try to protect against:",[285,937,938,952,960,968,977,983],{},[288,939,940,943,944,947,948,951],{},[291,941,942],{},"Other users and processes on the same machine."," The loopback API has no\nlogin, so anyone who can open a connection to it can drive Kraft.\n",[296,945,946],{},"$KRAFT_HOME\u002Frun"," itself is ",[296,949,950],{},"0700",", so other users cannot read the databases\nand logs in it.",[288,953,954,957,958,305],{},[291,955,956],{},"An agent running without a sandbox."," It has your user's access; see\n",[301,959,279],{"href":548},[288,961,962,965,966,305],{},[291,963,964],{},"The agent CLI and its provider."," Kraft runs the CLI you installed. What\nthat CLI sends to its model provider, and what the provider keeps, is\nbetween you and the provider; see ",[301,967,263],{"href":264},[288,969,970,973,974,976],{},[291,971,972],{},"A repository's own commands."," Its ",[296,975,649],{}," and test commands run\nwith the worker's access, and a pre-push hook runs as you when Kraft pushes\nthe branch.",[288,978,979,982],{},[291,980,981],{},"Anyone who has your password or the bearer token."," Either one grants\nfull control.",[288,984,985,988,989,780,992,995],{},[291,986,987],{},"The machine and the forge."," A compromised OS, container runtime,\n",[296,990,991],{},"gh",[296,993,994],{},"glab"," login or git remote is outside what Kraft can check.",[276,997,999],{"id":998},"reporting-a-vulnerability","Reporting a vulnerability",[281,1001,1002,1003,305],{},"Report vulnerabilities privately, as described in\n",[301,1004,1007],{"href":1005,"rel":1006},"https:\u002F\u002Fgithub.com\u002FitsOmidKarami\u002Fkraft\u002Fblob\u002Fmain\u002FSECURITY.md",[664],"SECURITY.md",[1009,1010,1011],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":740,"searchDepth":760,"depth":760,"links":1013},[1014,1015,1016,1017,1018,1019,1020],{"id":278,"depth":760,"text":279},{"id":481,"depth":760,"text":482},{"id":669,"depth":760,"text":670},{"id":824,"depth":760,"text":825},{"id":887,"depth":760,"text":888},{"id":931,"depth":760,"text":932},{"id":998,"depth":760,"text":999},"Kraft's threat model: what it protects against, and what it deliberately doesn't.","md",null,{},true,{"title":259,"description":1021},"W5cYh2gxOHLsJNGxz6rEGI-vjD8pNyNWxehCIap-bJQ",[1029,1031],{"title":255,"path":256,"stem":257,"description":1030,"children":-1},"Where to find the contributor guide and the release process.",{"title":263,"path":264,"stem":265,"description":1032,"children":-1},"What leaves your machine, where it goes, how to turn it off, and where Kraft keeps secrets and state.",1790824542558]