Run command as sudo with php exec with provided password

I have a small php website and want to run a script via button press. On the website I have an input for a password and I want to use that password for sudo authentification. (I don’t want to change permissions somewhere to make this work. I just want to use plain sudo auth.)

I have this php script:

exec('echo "' . $request['password'] . '" | sudo -S /usr/local/bin/mycommand  2>&1', $output, $retval);

But this doesn’t seem to work. I can run this script without problems via console but just not via php. I also tried to hardcode the password rule out errors within the request but that also doesn’t work.

Those are the errors I get via php:

0   "[sudo] password for www-data: Sorry, try again."
1   "[sudo] password for www-data:"
2   "sudo: no password was provided"
3   "sudo: 1 incorrect password attempt"

What’s the error here?


Edit: I just noticed if the password contains a " it will escape the echo and one could exec commands as www-data user. I will probably just disallow " to fix this or is there a simple way to sanitize it?

You’re encountering several related problems here — both security and technical. Let’s go through the technical reason why your sudo call fails via PHP, and then address the security implications.


Why your sudo call doesn’t work via PHP

1. sudo requires a TTY

By default, sudo is configured (in /etc/sudoers) to require a tty for password prompts. This breaks any attempt to echo a password into it from a non-interactive process like PHP-FPM or Apache.

Check this setting:

sudo grep 'requiretty' /etc/sudoers /etc/sudoers.d/* 2>/dev/null

If you see:

Defaults requiretty

This must be disabled for PHP-sudo password use to even be possible. For www-data, you’d need something like:

Defaults:www-data !requiretty

You can safely add this using:

sudo visudo

2. sudo doesn’t accept password via echo reliably

Even without requiretty, sudo does not reliably accept passwords from stdin unless it’s running interactively. You’re doing:

exec('echo "' . $request['password'] . '" | sudo -S /usr/local/bin/mycommand  2>&1', $output, $retval);

This sometimes works in a shell because the shell can allocate a TTY and provide stdin correctly. PHP’s exec() doesn’t behave that way. In many configurations, especially under php-fpm, it won’t be able to pipe the password properly.


3. Sudo prompts for a password as www-data, not your own user

You’re authenticating as the www-data user. If www-data has no sudo rights or isn’t allowed to run /usr/local/bin/mycommand, then sudo will always fail even if the password is correct.


Why this is dangerous

Your note about allowing " in the password is a red flag.

You’re building a shell command using:

'echo "' . $password . '" | sudo -S ...'

This is vulnerable to shell injection. Even if you escape quotes, other characters like ;, backticks, or $() could still be exploited.

An attacker could craft a password like:

" | rm -rf / #"

And your code would effectively run that command as www-data.


Solutions

A. Don’t use passwords and sudo in this way

It’s not secure or reliable to run sudo with password authentication in PHP. If you’re OK allowing a specific command to be run by PHP, the proper way is:

1. Allow passwordless sudo for the specific command:

Edit with visudo:

www-data ALL=(ALL) NOPASSWD: /usr/local/bin/mycommand

2. In PHP, simply do:

exec('sudo /usr/local/bin/mycommand 2>&1', $output, $retval);

This is more secure and avoids storing or handling a password at all.

You can still require a password in PHP logic (not for sudo), and only run the command if the input password matches an expected value stored securely.

if (hash_equals($expected_password, $_POST['password'])) {
    exec('sudo /usr/local/bin/mycommand 2>&1', $output, $retval);
} else {
    http_response_code(403);
}

This avoids all the pitfalls: no TTY issues, no echo, no shell injection, no sudo password prompt.


B. If you absolutely must use passworded sudo

Not recommended, but:

  • Disable requiretty for www-data in sudoers.
  • Use proc_open() in PHP to manage stdin/stdout explicitly.
  • Escape everything rigorously.

However, this is brittle, and again: do not do this in production.


Conclusion

Your current approach fails because sudo expects a TTY and does not reliably read passwords piped via echo when run from PHP. Even worse, your method opens the door to shell injection vulnerabilities.

Best practice: allow passwordless sudo for specific commands (not general use), and control access via your PHP logic, not by trying to pass passwords to sudo.

Let me know if you want help writing the sudoers line safely or structuring the command restrictions.