Skip to content

fix: harden entrypoint output handling in fullsend action - #230

Closed
waynesun09 wants to merge 2 commits into
mainfrom
fix-action-entrypoint
Closed

fix: harden entrypoint output handling in fullsend action#230
waynesun09 wants to merge 2 commits into
mainfrom
fix-action-entrypoint

Conversation

@waynesun09

@waynesun09 waynesun09 commented Apr 13, 2026

Copy link
Copy Markdown
Member

Summary

  • Path traversal mitigation: validate that the CLI-returned artifact path is absolute before passing it to actions/upload-artifact
  • GITHUB_OUTPUT injection prevention: use heredoc delimiter instead of inline = assignment, preventing newline injection from CLI stdout

Note: the echo in ARTIFACT_DIR="$(echo fullsend entrypoint ...)" is an intentional stub — the fullsend entrypoint CLI subcommand is not yet implemented (see also internal/layers/workflows.go:175). These hardening fixes prepare the action for when the real command replaces the stub.

Test plan

  • Confirm the step fails with a clear error if the CLI returns a relative or empty path
  • Verify heredoc output format is correctly parsed by downstream steps

Hardens output handling introduced in #210.

The run-fullsend step used `echo fullsend entrypoint` which prints
the literal string instead of executing the CLI, making artifact
upload non-functional. Remove `echo` so the command actually runs.

Also add path validation (must be absolute) and use a heredoc
delimiter for GITHUB_OUTPUT to prevent injection via newlines in
CLI output.

Signed-off-by: Wayne Sun <gsun@redhat.com>
The echo is intentional — fullsend CLI does not have an entrypoint
subcommand yet. Revert the echo removal while keeping the path
validation and GITHUB_OUTPUT hardening fixes.

Signed-off-by: Wayne Sun <gsun@redhat.com>
@waynesun09 waynesun09 changed the title fix: execute fullsend CLI and harden entrypoint output fix: harden entrypoint output handling in fullsend action Apr 13, 2026

@ralphbean ralphbean left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Security hardening review — three issues to address before merging.

The approach is sound (heredoc delimiter for GITHUB_OUTPUT, absolute path validation), but there are gaps that leave the same injection vectors partially open. See inline comments.

echo "artifact_dir<<FULLSEND_EOF"
echo "${ARTIFACT_DIR}"
echo "FULLSEND_EOF"
} >> "${GITHUB_OUTPUT}"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Delimiter injection / no newline validation

The static FULLSEND_EOF delimiter can be forged if an attacker controls CLI stdout. If ARTIFACT_DIR contains FULLSEND_EOF on its own line, the heredoc terminates early and arbitrary GITHUB_OUTPUT variables can be injected — the same class of attack this PR is trying to prevent.

More fundamentally, ARTIFACT_DIR is not validated for embedded newlines or carriage returns, which is the primary injection vector.

Suggested fix (both layers):

# Reject paths with newlines/CRs
if [[ "${ARTIFACT_DIR}" =~ $'\n' || "${ARTIFACT_DIR}" =~ $'\r' ]]; then
  echo "::error::fullsend entrypoint returned a path containing control characters"
  exit 1
fi

# Use a randomized delimiter
DELIMITER="FULLSEND_EOF_$(head -c 16 /dev/urandom | xxd -p)"
{
  echo "artifact_dir<<${DELIMITER}"
  echo "${ARTIFACT_DIR}"
  echo "${DELIMITER}"
} >> "${GITHUB_OUTPUT}"

The newline rejection is the most important fix — it neutralizes delimiter collision as a secondary effect.

echo "artifact_dir=${ARTIFACT_DIR}" >> "${GITHUB_OUTPUT}"
# Validate path is absolute and within expected boundaries.
if [[ "${ARTIFACT_DIR}" != /* ]]; then
echo "::error::fullsend entrypoint returned a non-absolute path: ${ARTIFACT_DIR}"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Untrusted input in ::error:: annotation

ARTIFACT_DIR comes from CLI stdout and is untrusted. Interpolating it directly into a ::error:: workflow command could allow workflow command injection (e.g., if the value contains :: sequences or encoded newlines).

Suggested fix — log the value separately instead of interpolating it into the annotation:

echo "::error::fullsend entrypoint returned a non-absolute path (see logs)"
printf 'Rejected path value: %s\n' "${ARTIFACT_DIR}"

# Validate path is absolute and within expected boundaries.
if [[ "${ARTIFACT_DIR}" != /* ]]; then
echo "::error::fullsend entrypoint returned a non-absolute path: ${ARTIFACT_DIR}"
exit 1

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

No path canonicalization

A path like /tmp/../../../etc/shadow passes the absolute-path check. Consider canonicalizing with realpath and optionally enforcing a prefix:

ARTIFACT_DIR="$(realpath -m "${ARTIFACT_DIR}")"

The -m flag resolves logically without requiring the path to exist. This would also pair well with a prefix check (e.g., must be under ${GITHUB_WORKSPACE} or ${RUNNER_TEMP}) for defense-in-depth.

@waynesun09

Copy link
Copy Markdown
Member Author

Closing — the underlying pattern this PR was hardening no longer exists on main.

The action now uses fullsend run --output-dir "${GITHUB_WORKSPACE}/output", which passes a predetermined directory to the CLI instead of reading one from CLI stdout. This removes the attack surface (GITHUB_OUTPUT injection, path traversal from untrusted stdout, delimiter forging) that this PR and the review comments were addressing.

All three review findings from @ralphbean were valid for the old fullsend entrypoint pattern but are no longer applicable.

@waynesun09 waynesun09 closed this Apr 27, 2026
@waynesun09
waynesun09 deleted the fix-action-entrypoint branch April 27, 2026 19:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants