HOWTO: chroot SFTP (only) - Security Notes and FAQ

[Return to index]

Security Notes and FAQ

Since I first put this solution together, I have had a huge amount of feedback, and helped many people 'tweak' their installations to get them working. In all of this, there have been a number of common questions, which are documented below. Hopefully one or more of these answers will help you, but if not do feel free to get in touch.


  1. "This solution is useless - it doesn't help me at all!"
  2. "Why this whole sftpsh and chroot thing instead of just using sftp-server as the user's shell?"
  3. Possible conflicts with pre-packaged SSH implementations
  4. "I connect remotely to my server using SSH - how can I reinstall SSH while connected?"
  5. Security Bypass: Notes and Considerations
  6. Possible bypass: mail forwarding (and other functionality)
  7. Possible bypass: 'HOME' environment variable
  8. Received message too long 1936094320
  9. "I'm having problems with [such and such a Unix/Linux command]";
    "You seem to know about Linux/Unix systems - do you know how to [do an unrelated thing]?";
  10. Can you explain the whole 'magic token' thing in the user's home directory path?
  11. I get some weird error...

"This solution is useless - it doesn't help me at all!"

As described on the main page, this solution may not be right for everybody. Much of the feedback I receive is along the lines of "rssh is much better" or "You should really try JailKit", etc.

I considered lots of the existing solutions before being forced to devise this one, since none of them quite met my requirements. Key points to note about the environment I wanted to construct are:

  • My users require SFTP access to the server only - using the principle of least privilege (as every good SysAdmin should!), I would prefer not to give them anything more than that;
  • The server provides only two services for my users:
    1. Web hosting (so file upload/download is crucial); and
    2. For some users, simple secured storage (for file sharing between locations).
    E-mail services, domain name management, etc. are all handled through different means, and not managed via this interface (and in some cases, not even by the same server). It is worth noting the later point about a possible security bypass related to e-mail services.
  • My users do not require any profile-based configuration (.* files in their area), and indeed these are not used by the custom shell.
This scenario may not be the same as yours, and so of course the solution may not be right for you. Please don't have a go at me if a pure chroot'd SFTP solution doesn't serve your business requirement - I can't be all things to all people!

"Why this whole sftpsh and chroot thing instead of just using sftp-server as the user's shell?"

The shell you assign to the user is actually critical to this whole process. The way SFTP works is rather strange - the client connects using standard SSH, and then asks the server to execute the sftp-server subsystem. Since you are permitting the user shell access, there are all sorts of other things they could do rather than execute the SFTP subsystem.

If you set sftp-server to be the user's shell, the user is (I'm told) still able to use some of SSH's own built-in functionality to do things on your system, such as execute shell commands, etc. before loading the SFTP subsystem. If you want to give it a go, though, Andres Tarzia put together a variant on sftp-server.c that is intended to act as the user's shell, and limit their activity through code, rather than chroot. Simply download, rename to sftp-server.c and compile SSH as normal (no need to follow the rest of my approach).

So, you might say, why not just jail sftp-server with chroot (using my code)? Because the user will still be opening an SSH connection, with other operations available, before the subsystem is even called.

OK, then, let's jail the whole SSH shebang, you might say... Well, this is the method I started out with, but an inevitable part of this is that you have to make a whole bundle of libraries available in the user's home area, as well as some system files their shell expects to find. Some of these libraries might give them the ability to do other things (I've never really tested) but the main problem was that users kept deleting them by accident! Since the user has to own their home area, they are able to delete anything at all.

So, in the end, I came to one conclusion - give the users a shell that only allows them to execute sftp-server, jail sftp-server so it has no access to anything, and we should be sorted. Since sftp-server is jailed, trying to execute a shell command won't do anything, and we're dropping sftp-server's privileges again once it's running, so even if the user managed to drop out to a shell, their shell would be sftpsh which only allows them to run sftp-server!

Possible conflicts with pre-packaged SSH implementations

Most systems (Linux, Solaris, BSD, etc.) will come pre-installed with some form of pre-packaged SSH daemon. When following my method, which is based on a compilation from scratch, it is best to remove any existing package to avoid later conflicts (such as multiple daemons, differing sshd_config files, etc.). Use whatever package management command you usually do (yum, apt-get, etc.).

Some of the solution variants base themselves on the official packages (by downloading source code first), which will reduce the potential for conflict - you'll need to assess the best solution for you.

Obviously this is all going to be a bit tricky if your only connection to your server is remotely using SSH! The next answer discusses this issue...

"I connect remotely to my server using SSH - how can I reinstall SSH while connected?"

This is an awkward situation - by far the safest approach is to perform the configuration at a console, but it won't be possible for everyone (in my own case, I did all the work over an SSH connection, with my ISP's number at hand if things went wrong!).

If you have an existing SSH installation that you're going to modify, things aren't too tricky - you can rebuild and reinstall SSH while connected, and as long as the full build process is successful, simply HUP or restart the SSH daemon - this shouldn't affect the connection you're currently using, but will allow you to test the new installation before disconnecting.

If you have a pre-packaged installation of SSH in place that you want to remove, the situation is a little more difficult. I haven't tried remaining connected after removing SSH (in theory, the binary should remain in memory until you disconnect, even if you uninstall it). In this situation, it might be worth considering temporarily switching on telnet (perhaps on an 'unusual' port number), unless data interception is a realistic threat in your situation.

Security Bypass: Notes and Considerations

There are lots of well-documented ways of breaking out of a chroot jail, and I've had a crack at trying each of them against this solution. As far as I can tell (and I'm no expert), this isn't easily possible (if at all). Even if a user was able to break out of SFTP, or the chroot jail, the sftp-server subsystem drops privileges so that they would still have the correct user rights - their shell, however, is 'sftpsh', and so they could only execute sftp-server anyway!

I would be very interested to hear from anyone that can think of a way users (or, God forbid, outsiders!) could break this solution, as I'd love to find a way to resolve it.

I've heard lots of suggestions about ways a user could break the system, but so far (thankfully) none of them have worked - the combination of sftpsh, sftp-server and chroot seems to be pretty robust.

Do note, though, that two viable security risks have been pointed out to me: although they're not a realistic consideration in my environment, they might be in yours (please see the next two sections).

One important configuration option, though, to reduce the potential for users to 'play' with your system is to use AllowTcpForwarding no in your sshd_config file, otherwise users may be able to connect to other daemons on your system.

Possible bypass: mail forwarding (and other functionality)

As described earlier, the only service offered to users in my environment is file upload/download - mail and other services are handled through other means.

Be warned that if you have a fairly typical e-mail setup, your users may have the ability to create a .forward file in their local area, enabling them to route their e-mail or (of more concern) pipe inbound e-mail to a file or system executable.

In this scenario, where you intend to offer your users other services that operate from their home directory, your SFTP environment may not actually be as isolated as it could be.

I haven't played with the possibilities on this front, as it doesn't apply to my environment, but do consider carefully what other programs on your system may operate on any files in your users' areas.

Possible bypass: 'HOME' environment variable

I received a message from someone looking into using my solution on their system, and they raised a valid concern:

"My main concern is how you access $HOME using getenv("HOME") which if someone were to gain local access would leave you vulnerable to any problems in getenv since the binary is setuid.

A safer would would be using getpw passing in the return of getuid, this would mean the home directory data would be loaded from /etc/passwd instead of what the user may have set in the environment."

This is indeed true - if a user could get access to a shell other than 'sftpsh', or could set their 'HOME' environment variable by some other means, they could modify the behaviour of the chroot'ing function.

In my environment, I don't think this is a major concern, as I don't believe users can get access to environment variables. However, for anyone that has a different situation where their users may be able to do so, I was also provided with the following code that can be used to modify sftp-server.c to work around the issue (but note the disadvantages that are indicated afterwards):

  char *user_dir;
  // Get the users home dir
  struct passwd *user_passwd;
  user_passwd = getpwuid(getuid());
  strcpy(user_dir, user_passwd->pw_dir);

  if (strcmp(user_dir, "") == 0)
    fatal("No homedir set for %s", user_passwd->pw_name);

  // change to homedir
  if (chdir(user_dir) != 0)
    fatal("Couldn't chdir to user directory %s: %s", user_dir, strerror(errno));

  // chroot to homedir
  if (chroot(user_dir) != 0)
    fatal("Couldn't chroot to user directory %s: %s", user_dir, strerror(errno));

  setenv("HOME", "/", 1);

I considered using this myself, but it fundamentally modifies the way the solution works, and would no longer be useful in my environment:

  1. The 'magic token' is no longer used, since users are chroot'd to their home directory only, whereas I use the flexibility provided by the '.' in their home path; and
  2. All users will be chroot'd when using SFTP, whereas I need to be able to permit one or two users to work outside the chroot'd SFTP solution.

This is, however, an excellent solution to a potential problem, and it may well be good for your situation.

Received message too long 1936094320

There are 3 things to check when you get this error, in order of likelihood - as far as I know, your problem will be one of these (if not, do contact me if you work it out!):

  1. Make sure you have the correct path to sftp-server in your sshd_config (note also the points above about conflicting SSH versions on the same machine)
  2. Did you remember to issue the chmod +s /path/to/your/sftp-server command?
  3. Have you set the permissions on the user's chroot'd home directory so that they are the owner?

In case it's of interest to anyone what the error actually means, your SFTP client is expecting to receive a 'Message Length', and receives the above number, which it deems to be too long.

What it's actually being sent, though, is some ASCII text - 1936094320 in hexadecimal is 73 66 74 70, which translates to the ASCII characters 'sftp'.

Your SFTP client is actually receiving the beginning of an error along the lines of 'sftp subsystem could not be started' or 'sftp subsystem could not be found'.

"I'm having problems with [such and such a Unix/Linux command]";
"You seem to know about Linux/Unix systems - do you know how to [do an unrelated thing]?";

Google is your friend! Do try searching around, use your 'man' facility, look for help on the Internet first - I only have a certain amount of time to respond to such things! I'll honestly try and help out where I can, but I have a day-job to attend to from time to time, and I'm by no means an expert myself!

Bear in mind that if you ask me a question I'm not immediately sure about, I'm probably only going to go and search using Google anyway, so why not cut out the middle man?!

Can you explain the whole 'magic token' thing in the user's home directory path?

OK, here's what happens... When your user logs in, their chroot 'jail' is created at the position of the full stop in their home directory path. They won't be able to access anything before the dot, but will be able to see everything after the dot. The directory they will see when they first log in is the full path.

Take, for example, the following definition for a user's home directory:


The user 'jimmy', on logging in, will initially see files in wwwroot, and will be able to traverse up one level (to ../jimmy) but no further - this will appear to him to be the root directory of the file system.

You could, however, specify the following:


Jimmy would still see his wwwroot directory content when logging in, but also be able to traverse up two levels (to ../../users), possibly enabling him to see the home folders of all users on the system (I hope you set your file permissions properly!).

My own usage is more along the lines of:


In this example, jimmy is placed in his home folder when logging in, and can go no higher. In my scenario, some users have multiple Web sites, and so they will immediately see folders along the lines of,, etc.

I hope these examples clarify the situation!

I get some weird error...

I'm not an expert by any means, and so troublehooting (especially without hands-on access!) can be very tricky. Again, I'll do my best to help out, but it would be helpful if (before contacting me) you could:

  • Double-check you followed the full process described on the main page, without skipping or modifying any steps;
  • Ensure you're using my patched version of sftp-server.c and sftpsh.c;
  • Make sure you have no conflicts between multiple versions of SSH on your system; and
  • Read through all the other earlier entries on this page to make sure I haven't already covered your issue.

Many thanks!

PGP/GPG Public Key [4096/4096 RSA]
Contact The Minstrel
Web The Minstrel's Showcase