Repository navigation
fix(cli): print titles and names without what terminals act on - #358
Merged
Merged
Conversation
Session titles reached the terminal as the server had them: `fctl sessions`, `fctl show`, `fctl attach` and the host commands printed them raw, and titles the control plane makes itself (from a prompt, a Linear ticket's title, a schedule's prompt or a reviewed pull request's title) skipped the control-character check that titles people set get. A project editor, the author of a reviewed pull request or whoever writes a Linear ticket could put escape sequences in a title that set another member's clipboard, rewrite their screen or plant links when they listed sessions. Titles fctl makes now leave out control characters and those that turn text around, and the CLI prints titles, descriptions, branches, names and what `fctl login` shows through `style::plain`, and error messages through `terminal_safe`.
|
fctl reviewed The domain side ( On lines the diff doesn't show:
Reviewed by fctl · Review agent settings |
The line `fctl run` prints for the session it started, and what `fctl edit` prints of a session's new title and description, still went to the terminal as the server had them; both go through `style::plain` now, as in `fctl show`.
Contributor
Author
|
On the review's two summary findings, both fixed in 10587ed: the line |
kalaspuff
approved these changes
Oct 30, 2026
kalaspuff
pushed a commit
that referenced
this pull request
Oct 30, 2026
## Summary What a linked Linear account delegates to fctl, or mentions fctl in, starts sessions as its fctl person, on their Claude subscription, and its replies reach their sessions' agents. With a stolen browser session or token, someone could link their own Linear account to the victim's fctl account, with nothing to confirm and nothing said to the person, and go on starting the victim's sessions from Linear, reading what they do there, long after the stolen token was revoked or the password changed. Linking a Linear account is now a sensitive action (`Sensitive::LinkLinear`), as connecting a Claude subscription became in #326: where the primary instance owner turned on confirming it's you, it takes a passkey or a code. The app's "Link your Linear account" buttons (Settings and a project's Tickets tab) confirm before they go on to Linear; a link opened elsewhere (Linear's own button in an agent session, `fctl account linear connect`) goes back to Settings with "Linking a Linear account takes confirming it's you", where linking again confirms first. A new link also emails the person when email is set up, naming the Linear account and saying what it does. Verified in `cargo xtask dev`: with confirming turned on and an authenticator app on the account, an unconfirmed session's `GET /api/v1/linear/link` goes back to `/settings?linear=confirm#linear`, and after `POST /api/v1/auth/verify` it goes on to Linear's sign-in. The web tests for the Tickets tab and the outcomes pass, and `cargo xtask check --quick` passes. The email needs an instance with email, which the dev stack isn't. The privacy policy lists the new email since: - hyperstructure/fctl-site#97 ## Worth confirming - **Decision:** like every sensitive action, this asks only where confirming it's you is turned on, which is off by default; elsewhere the email is what tells the person. - **Decision:** a link from Linear's own button that needs confirming lands on Settings rather than taking up the agent session that asked for it; after linking from Settings, fctl still takes up the delegations that waited for that Linear account. ## Stacked pull requests The fixes before this one in this security pass are on main; the next ones build on this one: - #358 - #359 - #360 [fctl session](https://app.fctl.sh/s/ses_01M677K9YMM5WPZBTAR2KKXMSZ) <!-- FCTL_REVIEW_SUMMARY --> --- > [!NOTE] > **Medium risk.** It adds a confirm-it's-you check to linking a Linear account, which changes an authentication-adjacent flow for everyone who links one; a mistake could block linking or let a stolen session link an account. > > **What it does.** Linking a Linear account lets Linear delegations start sessions as the person, so `GET /api/v1/linear/link` now requires the same sensitive-action confirmation as connecting a Claude subscription, where the instance asks for it. The web app confirms before sending people there, and Linear's own button is redirected back to Settings to confirm. A notice email is also sent when an account is linked. > > **New outcome and email.** Linking now has a `confirm` outcome shown in Settings and sends a best-effort email to the person; docs/security.md and docs/architecture.md are updated. > > <sub>[fctl review](https://app.fctl.sh/s/ses_01M67D37HF57SP912A3YYJK0WN)'s first look at [`393e78c`](393e78c) · 10 files, +173 −11 · [Review agent settings](https://app.fctl.sh/p/fctl?tab=reviews)</sub> <!-- /FCTL_REVIEW_SUMMARY --> --------- Co-authored-by: fctl-sh[bot] <343971779+fctl-sh[bot]@users.noreply.github.com>
kalaspuff
pushed a commit
that referenced
this pull request
Oct 30, 2026
…359) ## Summary The device page warns against approving a CLI sign-in someone else started, but its other use had no such warning: a "confirm it's you" request, which any CLI or unlimited access token that is signed in already can start (`POST /api/v1/auth/verify/device`) and send as a link. With a leaked CLI or access token, on an instance that asks to confirm sensitive actions, someone could send its owner that link: one approval gave the token 15 minutes of sensitive actions, such as making an access token that outlives revoking the leaked one, which the confirmation is there to stop. The page now says what approving allows and to deny a request you didn't make yourself, in a terminal, just now. Verified in `cargo xtask dev` with a confirmation code started from the dev token: the screenshots below are of `/device?code=…`, main against this branch. `npm run check` in `web/` passes. ## Screenshots At e6ecbc0, the device page for a confirmation request, 900 px wide. | Before | After | |---|---| |  |  | |  |  | At a phone's width, dark:  ## Stacked pull requests Based on the one before it in this security pass's stack: - #358 [fctl session](https://app.fctl.sh/s/ses_01M677K9YMM5WPZBTAR2KKXMSZ) <!-- FCTL_REVIEW_SUMMARY --> --- > [!NOTE] > **Low risk.** It only changes the wording of a warning on the device page; no logic, API or stored data is touched. > > **What it does.** The device page already warned against approving a CLI sign-in that someone else started, but not against approving a confirm-it's-you request, which a signed-in CLI or token can start and send as a link. The confirmation text now says what approving allows (15 minutes of sensitive actions, such as making access tokens and exporting data) and tells people to approve only what they started themselves in a terminal, just now. > > <sub>[fctl review](https://app.fctl.sh/s/ses_01M67D4QBTA7H37DJ9VA0BHJ7K)'s first look at [`bb36116`](bb36116) · 1 file, +3 −1 · [Review agent settings](https://app.fctl.sh/p/fctl?tab=reviews)</sub> <!-- /FCTL_REVIEW_SUMMARY --> Co-authored-by: fctl-sh[bot] <343971779+fctl-sh[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Session titles reached people's terminals as the server had them.
fctl sessions,fctl show, the header offctl attachandfctl run, and the host commands' lists printed them raw, and the titles the control plane makes itself skipped the control-character check that titles people set get: one made from a prompt's first line, from a Linear ticket's title, a schedule's prompt or a reviewed pull request's title. So a project editor, the author of a pull request a review agent reviews, or whoever writes a Linear ticket that someone delegates could put escape sequences in a title that, when another member listed sessions, set their clipboard (in terminals that allow OSC 52), rewrote their screen, set the window's title or planted links.fctl_domain::naming::plain), as names already did.fctl loginshows (the instance's name, the code, the link, who signed in) throughstyle::plain, one line without any control characters, and error messages throughterminal_safe, as transcripts already were (fix(cli): open only the server's sign-in links and print sessions safely #174). Titles stored before this print clean too.Verified against
cargo xtask dev: a session started with a prompt that begins with an OSC 52 sequence gets a title without it, and with a raw escape sequence put into a stored title,fctl sessionsandfctl showprint it without any escape or bell character. New unit tests cover the domain's titles, review titles and the CLI'splain;cargo xtask check --quickpasses.Stacked pull requests
Based on the one before it in this security pass's stack:
fctl session
Note
Low risk. It only changes how titles and names are cleaned or printed, in the CLI and in the titles the control plane derives, with no stored-data or protocol change.
What it does. Titles the control plane derives from prompts, Linear tickets, schedules and reviewed pull requests now drop control characters and characters that reverse text, so escape sequences in them can no longer act on a terminal. The CLI also prints titles, descriptions, branches, names, models, login details and error messages through
style::plainorterminal_safe, now including thefctl runconfirmation line andfctl editoutput, so titles stored before this print clean too.fctl review's first look at
10587ed· 8 files, +114 −25 · Review agent settings