Hide arguments to program without source code

As explained here, Linux puts a program's arguments in the program's data space, and keeps a pointer to the start of this area. This is what is used by ps and so on to find and show the program arguments.

Since the data is in the program's space, it can manipulate it. Doing this without changing the program itself involves loading a shim with a main() function that will be called before the real main of the program. This shim can copy the real arguments to a new space, then overwrite the original arguments so that ps will just see nuls.

The following C code does this.

/* https://unix.stackexchange.com/a/403918/119298
 * capture calls to a routine and replace with your code
 * gcc -Wall -O2 -fpic -shared -ldl -o shim_main.so shim_main.c
 * LD_PRELOAD=/.../shim_main.so theprogram theargs...
 */
#define _GNU_SOURCE /* needed to get RTLD_NEXT defined in dlfcn.h */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <dlfcn.h>

typedef int (*pfi)(int, char **, char **);
static pfi real_main;

/* copy argv to new location */
char **copyargs(int argc, char** argv){
    char **newargv = malloc((argc+1)*sizeof(*argv));
    char *from,*to;
    int i,len;

    for(i = 0; i<argc; i++){
        from = argv[i];
        len = strlen(from)+1;
        to = malloc(len);
        memcpy(to,from,len);
        memset(from,'\0',len);    /* zap old argv space */
        newargv[i] = to;
        argv[i] = 0;
    }
    newargv[argc] = 0;
    return newargv;
}

static int mymain(int argc, char** argv, char** env) {
    fprintf(stderr, "main argc %d\n", argc);
    return real_main(argc, copyargs(argc,argv), env);
}

int __libc_start_main(pfi main, int argc,
                      char **ubp_av, void (*init) (void),
                      void (*fini)(void),
                      void (*rtld_fini)(void), void (*stack_end)){
    static int (*real___libc_start_main)() = NULL;

    if (!real___libc_start_main) {
        char *error;
        real___libc_start_main = dlsym(RTLD_NEXT, "__libc_start_main");
        if ((error = dlerror()) != NULL) {
            fprintf(stderr, "%s\n", error);
            exit(1);
        }
    }
    real_main = main;
    return real___libc_start_main(mymain, argc, ubp_av, init, fini,
            rtld_fini, stack_end);
}

It is not possible to intervene on main(), but you can intervene on the standard C library function __libc_start_main, which goes on to call main. Compile this file shim_main.c as noted in the comment at the start, and run it as shown. I've left a printf in the code so you check that it is actually being called. For example, run

LD_PRELOAD=/tmp/shim_main.so /bin/sleep 100

then do a ps and you will see a blank command and args being shown.

There is still a small amount of time that the command args may be visible. To avoid this, you could, for example, change the shim to read your secret from a file and add it to the args passed to the program.


  1. Read the documentation of the command line interface of the application in question. There may well be an option to supply the secret from a file instead of as an argument directly.

  2. If that fails, file a bug report against the application on the grounds that there is no secure way to supply a secret to it.

  3. You can always carefully(!) adapt the solution in meuh’s answer to your specific needs. Pay special consideration to Stéphane’s comment and its follow-ups.


If you need to pass arguments to the program to get it to work, you're going to be out of luck no matter what you do if you can't use hidepid on procfs.

Since you mentioned this is a bash script, you should already have the source code available, since bash is not a compiled language.

Failing that, you may be able to rewrite the cmdline of the process using gdb or similar and playing around with argc/argv once it's already started, but:

  1. This is not secure, since you still expose your program arguments initially prior to changing them
  2. This is pretty hacky, even if you could get it to work I wouldn't recommend relying on it

I'd really just recommend getting the source code, or talking to the vendor to get the code modified. Supplying secrets on the command line in a POSIX operating system is incompatible with secure operation.