Repository navigation
fix(amazonq): require workspace containment before opening chat card files - #2906
Draft
dungdong-aws wants to merge 3 commits into
Draft
dungdong-aws wants to merge 3 commits into
dungdong-aws wants to merge 3 commits into
Conversation
…files onFileClicked passed card paths to showDocument with no containment check. The fsRead branch opened params.filePath directly, the default branch opened params.fullPath directly, and resolveAbsolutePath joined a relative filePath onto the workspace root, so a traversing relative path escaped as well. Card paths originate in model tool results and service findings, so a manipulated response plus one click opened any readable file and fed it to completion context. All three open paths now go through openIfAllowed, which canonicalizes the path and reuses requiresPathAcceptance: a file opens only when it is inside a workspace folder or the user already approved it for the card's tool in this session. The user prompts directory is allowed for .prompt.md files, which resolveAbsolutePath deliberately resolves there. Refused clicks are logged and otherwise ignored. Tests cover an inside file, an outside fullPath, an escaping relative path, an fsRead card for an unapproved and an approved outside path, an fsWrite approval not unlocking an fsRead card, a prompt file in the prompts directory, and a non-prompt file in that directory.
|
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
The previous commit refused such opens outright and only logged. A card can legitimately point outside the workspace, for example a findings path the user wants to inspect, so the open is now gated by a warning dialog instead of dropped. openIfAllowed shows a showMessageRequest warning with Open and Cancel when requiresPathAcceptance requires acceptance. The message leads with the specific reason the check returned, such as the sensitive-file warning, and names the canonical path. Choosing Open records the path for the card's tool in the session's approved paths, so a repeat click or a later tool use on the same path does not prompt again. Cancel or dismissal aborts the open. In-workspace, already-approved, and prompt directory paths open without a dialog as before. MessageType and MessageActionItem are imported from the protocol module, which already supplied MessageType to this file; a second import from server-interface produced a duplicate identifier. Tests cover the dialog contents and action order, Open opening the file, Cancel and dismissal refusing, the choice being remembered across clicks, the sensitive-path reason surfacing in the dialog, and existing approvals suppressing the dialog.
Match single backslash separators consistently with session approval storage. Normalize Windows paths before sensitive-location pattern checks. Add session round-trip tests for drive and UNC paths and use native separators in the sensitive-path fixture.
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
onFileClickedopened chat file-list card paths with no containment check. Three paths reachedshowDocumentunchecked:fsReadbranch openedparams.filePathdirectly;params.fullPathdirectly;#resolveAbsolutePathjoined a relativefilePathonto the workspace root, so a traversing relative path such as../../etc/passwdescaped as well.Card paths originate in model tool results and service findings. A manipulated response plus one user click opened any file the server process could read, and opening it fed the file to completion context and the workspace-context upload.
All three paths now go through
#openIfAllowed, which canonicalizes the path withresolveCanonicalPathand reusesrequiresPathAcceptance. A file inside a workspace folder, or one the user already approved for the card's tool in the current session, opens directly. Any other path shows ashowMessageRequestwarning with Open and Cancel before opening. The dialog leads with the specific reason the check returned, such as the sensitive-file warning, and names the canonical path, so an injected path is legible rather than a reflexive click. Choosing Open records the path for the card's tool in the session's approved paths, so a repeat click or a later tool use on the same path does not prompt again. Cancel or dismissal aborts the open.The user prompts directory (
~/.aws/amazonq/prompts) is allowed for.prompt.mdfiles.#resolveAbsolutePathdeliberately resolves prompt files there, andrequiresPathAcceptancewould otherwise refuse them both as out-of-workspace and because/.aws/matches the sensitive-path patterns.Intentional behavior changes
fsReadcard for a path the user approved when the tool ran still opens without a dialog; an approval granted tofsWritedoes not unlock anfsReadcard for the same path, so that click prompts.infoand produces no further UI.Tests and verification
Twelve
onFileClickedcases using a real temporary directory as the workspace folder, since the containment check canonicalizes folders through the filesystem.showMessageRequestis stubbed to Cancel by default, so each refusal case means refused when the user declines: an inside file viafullPathopens with no dialog; an outsidefullPathis refused; a relativefilePaththat traverses out of the workspace is refused; anfsReadcard for an unapproved outside path is refused; the same card after the user approved the path forfsReadopens with no dialog; the same card when the path was approved only forfsWriteprompts and is refused; choosing Open shows a Warning-typed dialog naming the exact path with Open and Cancel in that order and then opens the file; dismissing the dialog without a choice refuses; an Open choice is remembered so a second click does not prompt again; a sensitive out-of-workspace path surfaces the sensitive-file reason in the dialog; a.prompt.mdin the prompts directory opens with no dialog; and a non-prompt file placed in the prompts directory is refused.The gate decision was also exercised directly outside the Mocha harness with a real temporary workspace: inside file opens; outside file refused; traversing relative path refused; outside file approved for
fsReadopens; outside file approved only forfsWriterefused.Prettier passed on both changed files. ESLint reported no errors; remaining warnings are pre-existing
import/no-nodejs-modules.Verification limits
tsc --noEmitpasses for the package, including both changed files. The Mocha suite was not run locally: the authoring host enforces memory-capped test invocation through a cgroup scope that the sandboxed session could not create, so it was refused rather than run uncapped. CI is the first execution of the added tests.The prompt-directory tests stub
os.homedir.getUserPromptsDirectoryreads it at call time, so this works, but it is the most environment-sensitive part of the test and the most likely place for a CI-only failure.Not verified in a running IDE.
Not changed
openFileDiffforfsWriteandfsReplacecards still takestoolUse.input.pathunchecked. That path was already subject to the write tool's own approval when the tool ran, and the diff shows content the tool already produced rather than reading a new file, so it is a different exposure and is left for a separate change if wanted.