So first, I realize that this question is slightly out of the ordinary for this site. I will explain the backstory to avoid the XY problem.

Over on Programming Puzzles and Code Golf, lots of users (especially me) like to answer programming challenges using vim, and since vim is great at manipulating strings, it does pretty well as a "Programming language" of sorts. However, testing these answers is a little bit of a pain. I've written 100+ keystroke answers in vim before, and actually typing this out to test it is a pain. Also, sometimes users who aren't as familiar with vim will make mistakes like pressing <C-a> instead of ctrl+a, or not starting vim with vim -u NONE -i NONE which can cause issues with mappings and registers.

So to remedy this, I'm working on a "vim interpreter" that you can run in your browser. You can enter in a sequence of keystrokes, such as iHello<esc>Yp, and the browser will display the text


But this creates a security hole. A malicious user could enter something like

:r !ls

to get a listing of files and directories on the server, and then something like

:e /foo/somefile.txt

To wipe out files. To get around this, initially I tried sourcing the following script before running the interpreter:

au BufReadPre * :q!
au BufWritePre * :q!

and calling neovim with

nvim -Z

to disable shell access.

However, then I found out the user could still enter

:noautocmd e /foo/somefile.txt

So I added this to the script:

cmap noautocmd q!<cr>
cmap noa q!<cr>

But, a user can still get around this with

:cunmap nog<bs>a

(The g<bs> to get around 'noa' being remapped as you type it)

So I added

cmap cu q!<cr>
cmap cunmap q!<cr>

This works as far as I know, but it feels like I'm just polishing poop and adding duct tape. So my two questions are

  1. Is my current method secure, or are there ways to get around what I have right now?

  2. Is there a better way to accomplish this? If this is a linux-based solution (the server is running ubuntu), rather than a vim-based solution, that's okay I guess, but since I don't own the server it will be running on, I'd rather have it be a vim-based solution, since I'm more in control of that and it's less work on the server-owner's part.

  • 1
    You probably should go with something *nix like. For example: chroot --userspec vim:vim /var/myvimjail/, after creating a user called vim and allowing him only that directory. I'm not adding this as an answer because it requires user creation and you said you do not own the server.
    – grochmal
    Jun 29, 2016 at 18:02
  • You can safely forget it. VimL is Turing complete, and what you want to do is equivalent to the halting problem. Not going to work. Jun 29, 2016 at 18:55
  • @SatoKatsura I don't see how that's relevant. Brainfuck is turing complete, but has no security issues or file access.
    – DJMcMayhem
    Jun 29, 2016 at 18:57
  • (1) Brainfuck can't do what Vim can. (2) How do you know Brainfuck doesn't have security issues? (3) Feel free to ignore me. I'm just an old fart that has been around way too long after all. :) Jun 29, 2016 at 19:12

1 Answer 1


Have you looked at :h :sandbox?

These items are not allowed in the sandbox:
  - changing the buffer text
  - defining or changing mapping, autocommands, functions, user commands
  - setting certain options (see |option-summary|)
  - setting certain v: variables (see |v:var|)  *E794*
  - executing a shell command
  - reading or writing a file
  - jumping to another buffer or editing a file
  - executing Python, Perl, etc. commands

If that's too restrictive, I would use a chroot like @grochmal said. But, I suppose you have other options:

  • Fork Vim and neuter file reading functions so they fail as if a file wasn't found.
  • Fork Vim and alter the sandbox behavior to allow changing buffer text.
  • Create a docker container that has no volumes and is destroyed after a session.
  • 1
    ... Except :sandbox only applies to expressions. Jun 29, 2016 at 19:38
  • @SatoKatsura what's your point?
    – Tommy A
    Jun 29, 2016 at 20:14
  • My point is, the OP wants to sandbox a script. :sandbox doesn't work for scripts. It only works for expressions. Jun 29, 2016 at 20:21
  • I pointed out the sandbox feature as a way to restrict access. Loading files and scripts would be an implementation detail left to him. One method I can think of is: execute 'sandbox' join(readfile('script.vim'), '|')
    – Tommy A
    Jun 29, 2016 at 20:29
  • ... Which would only protect the join operation. Jun 29, 2016 at 20:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.