Skip to content

Fix CLI security hardening findings#5

Merged
altaywtf merged 2 commits into
mainfrom
fix/security-findings-followup
May 8, 2026
Merged

Fix CLI security hardening findings#5
altaywtf merged 2 commits into
mainfrom
fix/security-findings-followup

Conversation

@altaywtf
Copy link
Copy Markdown
Member

@altaywtf altaywtf commented May 8, 2026

Summary

Fixes the current putio-cli security hardening findings around installer permissions, terminal control handling, pagination bounds, non-PII agent runtime proofs, and manual release backfill input handling.

Changed

  • Normalize installer-created executable permissions to 0755 and reject group/world-writable install directories unless explicitly opted in
  • Neutralize terminal control bytes for untrusted terminal-rendered values and avoid reflecting raw rejected --fields payloads
  • Bound aggregate and NDJSON --page-all pagination by pages/items and reject repeated cursors
  • Narrow runtime proof docs to whoami --fields auth --output json
  • Use the validated backfill release tag output for checkout, packaging, and upload steps

Risks

  • Terminal rendering now strips control sequences from API/user values before display; reviewers should check that trusted CLI styling is still preserved
  • Large --page-all reads now fail once they exceed the configured page/item guardrails
  • Installer now rejects shared writable install dirs by default; intentionally shared setups must opt in

Verification

  • vp run verify
  • Built CLI rejected an OSC/CSI/CR --fields payload with no raw control bytes in stderr
  • Installer smoke blocked a shared writable install dir and installed dir/binary as 755 under umask 000
  • .github/workflows/backfill-release-assets.yml parsed as YAML

Complexity

Reduced: the release/input trust boundaries and runtime safety checks are explicit and covered by focused regression tests.

Copilot AI review requested due to automatic review settings May 8, 2026 23:17
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Addresses CLI security hardening findings across terminal output handling, pagination guardrails, installer permissions, and release tooling/doc guidance to reduce injection and runaway read risks.

Changes:

  • Harden terminal rendering by stripping control/escape sequences from untrusted, terminal-rendered values while keeping structured output safely escaped.
  • Add pagination guardrails for --page-all (max pages/items) and detect repeated cursors for both aggregate and streaming modes.
  • Tighten installer-created permissions and validate release tag inputs/propagation in the backfill workflow; update docs to use scoped whoami reads.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/internal/output-service.ts Adds terminal escape/control stripping, separates redaction from structured sanitization, and adjusts terminal/error rendering paths.
src/internal/output.test.ts Adds regression tests for control stripping in terminal mode and safe escaping in JSON output.
src/internal/command.ts Adds cursor pagination budgets and repeated-cursor detection; adjusts --fields validation labeling.
src/internal/command.test.ts Adds tests for non-reflection of control-bearing --fields and repeated cursor rejection.
src/command-paths.test.ts Adds end-to-end CLI path tests for repeated cursors and item-budget overflow during streamed paging.
install.sh Normalizes install dir/binary permissions and rejects group/world-writable install dirs unless opted in.
.github/workflows/backfill-release-assets.yml Validates tag name once and reuses validated output for checkout/packaging/upload; reduces reflection in validation error.
README.md Updates whoami example to a scoped, structured read.
AGENTS.md Narrows runtime proof command to whoami --fields auth --output json.
skills/putio-cli/references/reads.md Updates read guidance examples to use scoped whoami and structured output.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/internal/output-service.ts Outdated
Comment on lines 77 to 79
const isPlainObject = (value: unknown): value is Record<string, unknown> =>
typeof value === "object" && value !== null && !Array.isArray(value);


export const renderTerminal = <A>(value: A, renderTerminalValue: (value: A) => string) =>
sanitizeTerminalText(renderTerminalValue(value));
redactSensitiveText(renderTerminalValue(sanitizeTerminalValue(value) as A));
Comment thread src/internal/command.ts Outdated
Comment on lines 206 to 212
...new Set(
parts.map((part) =>
validateSafeString({
label: `\`--fields\` selector \`${part}\``,
label: "`--fields` selector",
pattern: TOP_LEVEL_FIELD_PATTERN,
patternMessage:
"`--fields` only accepts top-level field names without dots, brackets, or slashes.",
Comment thread install.sh
Comment on lines +116 to +130
if [ ! -d "$INSTALL_DIR" ]; then
mkdir -p "$INSTALL_DIR"
chmod 0755 "$INSTALL_DIR"
fi

[ -w "$INSTALL_DIR" ] || fail "install directory is not writable: $INSTALL_DIR"

permissions="$(ls -ld "$INSTALL_DIR" | awk '{print $1}')"
group_write="$(printf '%s' "$permissions" | cut -c6)"
other_write="$(printf '%s' "$permissions" | cut -c9)"

if { [ "$group_write" = "w" ] || [ "$other_write" = "w" ]; } &&
[ "${PUTIO_CLI_ALLOW_SHARED_INSTALL_DIR:-}" != "1" ]; then
fail "install directory is group/world-writable: $INSTALL_DIR. Set PUTIO_CLI_ALLOW_SHARED_INSTALL_DIR=1 to allow this intentionally."
fi
@altaywtf altaywtf merged commit 66f1459 into main May 8, 2026
6 checks passed
@altaywtf altaywtf deleted the fix/security-findings-followup branch May 8, 2026 23:27
@putio-release-bot
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.0.12 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants