Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions containers/agent/one-shot-token/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.so
18 changes: 18 additions & 0 deletions containers/agent/one-shot-token/one-shot-token.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,12 @@ static int tokens_initialized = 0;
/* Pointer to the real getenv function */
static char *(*real_getenv)(const char *name) = NULL;

/* Pointer to the real secure_getenv function */
static char *(*real_secure_getenv)(const char *name) = NULL;

/* pthread_once control for thread-safe initialization */
static pthread_once_t getenv_init_once = PTHREAD_ONCE_INIT;
static pthread_once_t secure_getenv_init_once = PTHREAD_ONCE_INIT;

/* Initialize the real getenv pointer (called exactly once via pthread_once) */
static void init_real_getenv_once(void) {
Expand All @@ -75,6 +79,15 @@ static void init_real_getenv_once(void) {
}
}

/* Initialize the real secure_getenv pointer (called exactly once via pthread_once) */
static void init_real_secure_getenv_once(void) {
real_secure_getenv = dlsym(RTLD_NEXT, "secure_getenv");
/* Note: secure_getenv may not be available on all systems, so we don't abort if NULL */
if (real_secure_getenv == NULL) {
fprintf(stderr, "[one-shot-token] WARNING: secure_getenv not available, falling back to getenv\n");
}
}

/**
* Initialize the token list from AWF_ONE_SHOT_TOKENS environment variable
* or use defaults if not set. This is called once at first getenv() call.
Expand Down Expand Up @@ -169,6 +182,11 @@ static void init_real_getenv(void) {
pthread_once(&getenv_init_once, init_real_getenv_once);
}

/* Ensure real_secure_getenv is initialized (thread-safe) */
static void init_real_secure_getenv(void) {
pthread_once(&secure_getenv_init_once, init_real_secure_getenv_once);
Comment on lines +186 to +187
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

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

secure_getenv() (below) relies on the token list to classify sensitive variables, but the token list is only initialized in getenv() via init_token_list() under token_mutex. As a result, if a process calls secure_getenv() before any getenv() call, num_tokens is still 0 and get_token_index() will always return -1, bypassing one-shot protection for sensitive tokens. Consider mirroring the getenv() initialization flow in secure_getenv(): lock token_mutex, call init_token_list() if needed, and compute token_idx while holding the mutex before deciding whether to pass through or apply one-shot behavior.

Suggested change
static void init_real_secure_getenv(void) {
pthread_once(&secure_getenv_init_once, init_real_secure_getenv_once);
static void init_real_secure_getenv(void) {
/* Initialize the real secure_getenv function pointer once */
pthread_once(&secure_getenv_init_once, init_real_secure_getenv_once);
/*
* Ensure the sensitive token list is initialized before any secure_getenv()
* logic relies on it. This covers the case where secure_getenv() is called
* before getenv(), which would otherwise leave num_tokens == 0 and cause
* get_token_index() to always return -1.
*/
pthread_mutex_lock(&token_mutex);
if (!tokens_initialized) {
init_token_list();
}
pthread_mutex_unlock(&token_mutex);

Copilot uses AI. Check for mistakes.
}

/* Check if a variable name is a sensitive token */
static int get_token_index(const char *name) {
if (name == NULL) return -1;
Expand Down
Loading