Is it safe to allow www-data to execute privileged commands?

This... is atrocious. The whole point of running Web things as a non-root user is damage containment: in case the Web server process gets hijacked through some vulnerability, at least the attacker won't obtain full control of the machine, since he will be constrained by the limitations of the non-root account www-data. But if you give www-data a way to run every command it wishes to, with the rights of any user (including root), and without any further authentication, then you just lost that damage containment feature.

To be fair, www-data + sudo is slightly better than simply running everything as root, because the going-to-root has to be explicit; therefore, common flaws like a PHP script writing files in improper locations would be harder to exploit. But still, making www-data a member of the sudoers looks like a poor idea.


When considering how secure something is, you should assume the attacker is able to log in as your www-data user, and have a shell. This does not mean your attacker really can get a shell, but there can be plenty of ways how the attacker can execute arbitrary shell commands; they could be results of library bugs like shellshock, or oversights in your code.

The safest way

The best way of doing this is, like @AlexeyVesnin said, to use a specialized process to do the work. Have this process listen on a (unix domain, so it isn't reachable from the network) socket, read its input from said socket, sanitize the input(!), do the work, and return some result to the socket, from where the web server script reads results. Any authorization (user needs to enter some password on the web site to be allowed to do this) should be handled in that process, and the www-data user should not be able to read any of that authorization data.

The mostly-safe sudo way

In case your budget, or your skill, doesn't make this best approach feasible, using the sudo approach isn't completely wrong, but you should restrict sudo permissions to the minimum you actually need. For example, let's assume you want to show current disk I/O data on your web site, for which you need to call iotop:

  • make a script, in this example /var/www/bin/get-disk-io, that extracts the data you need:

    /usr/sbin/iotop -b -n 1 | /usr/bin/head -2

  • Do not allow the caller of the script to pass any parameters, i.e. the script shouldn't access $1, $2, ... , $*, $@
  • In case you absolutely have to use parameters, sanitize them in your script first. Especially pay attention to whitespace or any unusual characters that might be hidden in parameters.
  • Make sure to state the full path to every command in that script, so attackers can't replace any of those commands with their own
  • Allow access to this script, and only this script, in /etc/sudoers
  • Make sure env_reset is in the defaults policy in your sudoers file

Note that this is still safer than a suid program, since (a) you can restrict who can execute it, so an attacker who gains the ability to execute a program under a different user won't be able to use it, (b) you can't pass arbitrary parameters to it, (c) the environment is sanitized by sudo, and (d) you can make sudo log when the command gets executed, so you have an audit trail that a suid program doesn't give you.

The suid way

Note: Do not do this unless you know what you're doing. If you're asking, or reading, this question on stackexchange, you probably don't. So don't do this.

If you set the owner of an executable to a certain user (chown user /my/executable/file), then set the suid bit (chmod u+s /my/executable/file), then that program will run under the permissions of that user every time it is executed. So, for example, chown root /bin/cat; chmod u+s /bin/cat will run every invocation of cat with root rights, which means you can read every file on the system independent of its access rights. Do not try this on a system that is connected to a network, not even for 5 minutes to "check if it works".

  • On many unix systems, this works for compiled programs only, not for scripts that need an interpreter
  • In some configurations, for example if you run the program under strace, the s bit has no effect
  • In NFS configurations, root often doesn't have access to files on the NFS server, so this might even reduce what you're able to do.

The restricted-suid-Linux way

Linux has a capabilities system, that works almost like suid, but a much finer granularity. For example, if you need a process to be able to use port numbers below 1024, in classical unix systems, you need to run the command as root, often meaning you need to do the above chown/chmod u+s stuff, which allows using those port numbers, but also grants access to the filesystem. Linux allows you to give the port capability without everything else that comes with root:

setcap cap_net_bind_service+EP /path/to/my/program

Do man 7 capabilities to learn more. If you seriously consider giving suid to a program, think twice if setting a capability isn't a better idea.


Every time, with no exception, when you see ALL=(ALL) NOPASSWD: ALL in the /etc/sudoers file, someone deserves to be fired. Basically, you have a second root user.

Is it safe? Hell no. Does it create a vulnerability? Hell yes.

You can use sudo to safely grant a non-root user (including www-data) a privileged execution, but it should always be as specific as possible. If you need to run /usr/bin/my_system_tool +x /var/cache/my_cache as root for whatever reason, that exact command, including parameters should be in the /etc/sudoers file.