Long time Emacs Lisp coder here. Here is a summary of the vulnerability described in the OP:
Anyone wishing to inspect an untrusted file of Emacs Lisp code
is likely to use Emacs to do the inspecting, but if
either of the popular packages Flymake and Flycheck is enabled,
merely opening the untrusted file gives the author of the file
the ability to run arbitrary code (because macros are tricky).
Even if an Emacs user avoids Flymake and Flycheck, the standard
emacs facility for "completing" the names of functions and variables
has the same basic vulnerability. Specifically, if the user uses Emacs to open the file, then types the start of the name of a function or variable, then types M-tab (i.e., presses the escape key, then presses the tab key) which attempts to fill in the rest of the name so that user does not have to manually type out the whole name, the arbitrary code is run.
It is clear to me (who was never tempted to use Flymake or Flycheck) what remediation I want: namely I want this "M-tab" functionality (which I have been using and probably most Emacs users have been using) to refrain completely from expanding any macros even
though doing so will prevent it from finding out the names of some of the functions
and variables I might be trying to insert with the result that sometimes I will have to type out the full name of the function or variable, without assistance.
>AFAICT the earliest public discussion about the security implications of Emacs Lisp macros started in August 2018, when Wilfred Hughes noted that code completion can lead to arbitrary code execution via macro-expansion.
The fact that the maintainers have yet to fix this is one more sign added to a list of 5 or 6 other signs that make me want to migrate away from Emacs.
Giving the maintainers the benefit of the doubt, I think the optimal solution solution would require a lot of thought and work. While I have no doubt that Elisp is an environment especially ripe for these kinds of exploits, it's by no means unique to Emacs. Just look at VSCode's solution to this problem: https://code.visualstudio.com/docs/editor/workspace-trust .
I have no doubt that VSCode has a much less risk of executing code by opening something. Ironically however, it seems that VSCode's extension is the most effective channel to distribute malware in the history of code editors. [1] [2]
Not that MELPA couldn't be used to distribute malware either, I just think, as another poster mentioned, these problems are almost more social than technical.
Emacs is just too old to be architected with security in mind. It's a great editor, but has baggage that IMHO can't be addressed on the spot.
Working on a codebase where you can't (heavily?) break things between any commit imposes such a slow pace that it's not completely unreasonable to start from the ground up and just study what made Emacs great and what didn't work too well.
It's surprising how long Emacs has been around and how good of an editor it is. It really makes rewrite attempts such a long stretch that it exhausts the motivation and time out of spirited folks that give it a go, but I think that given how complexity is being modularised and moved out (LSP, DAP, grammars) and newer languages make packaging easier that Emacs will eventually be replaced, definitely without covering everything it can do, but being strong at the average editing session.
That's my opinion as well. I run Emacs 24/7 but I do so inside Firejail, with no network access. It's not architected with security in mind and exploits are too easy.
The same can be said about the Linux userland. The Unix model of giving plenty of access to resources and any user file to user processes is outdated.
I find it frustrating something like Firejail or bwrap is not standard. I don't want a compromised program to have easy access to e.g. my SSH keys.
>Emacs is just too old to be architected with security in mind.
Bad security is endemic to all GNU projects. gnutls and gnupg come readily to mind, for example. In fact there was an article/blog post making the rounds a few years ago about how the letters "GNU" are an excellent heuristic for broken security models and fatally-flawed crypto.
What about GnuTLS and GnuPG do you think makes them insecure? I think that they offer something unique and that must be factored in; i.e. if you compare them to competitors, you can't compare apples to oranges when making judgments for them. In mind I have projects like Open/Bear/Boring SSL to compare GnuTLS with, and sequoia for gpg. I really like sequoia, but it offers a different product to gnupg.
Emacs is a mosaic of 50 years of computer history, security is not its priority, but I guarantee you that in bug-gnu-emacs any security/network-related patches are most welcome.
Good call to prevent macro expansion. Does also no big harm nowadays as there are several other ways to get good auto completion, e.g. copilot. Other than that no need to restrict functionality for power users.
I'm a lot less worried about this than I am about MELPA packages being targeted. But any other editor that incorporates a package manager exposes the same threat surface, and just about all of them are a lot more popular (thus more worth targeting) than Emacs.
It looks like adding a defcustom that would disable macro expansion, and basically any attempts to eval the code being edited, should not be a lot of work, or at least doable. Disable it in your config, get a nerfed-down but shields-up elisp editing mode.
Am I missing anything here? E.g. should I expect pieces of C code that handle completion in elisp mode?
I expect that the entire mode is implemented in elisp-mode.el. It's based on lisp-data-mode, but I don't expect that to handle macros (should check though).
Looking at elisp-completion-at-point and likely deeper into elisp--completion-local-symbols, I'd try to find where macroxpansion occurs, and made it conditional. Same for the explicit emacs-lisp-macroexpand.
I would also search for `(eval ` in general and maybe put it under a buffer-local flag, too, so that you won't press C-x C-e or C-M-x and execute malicious code by mistake, when you know you're working on a piece of malicious code.
Maybe instead of a defcustom, it should rather be a minor elisp-paranoid-mode which would do all kinds of things to prevent execution of the code in the buffer, or the code the buffer refers to, etc.
Doesn’t vim also have some ability, easily abused, to put a script at the top of a file, and it’ll just run when you open the thing?
This seems like a really useful functionality to have in the context where you actually do trust the files, but it is wildly insecure and an unexpected trapdoor, to have simple files executing things when you open them with a simple text editor…
Probably going to add similar protections here? Basically, I'd assume if it is your first time visiting a file, macros won't be expanded during autocompletion.
I dunno. I can see why this functionality might be useful, but I kinda think distros should disable it by default/make it whitelist-only.
I think the implications are really unexpected for “new” users (where “new” could be pretty generously defined, I mean, I know a couple people who use vim IRL, I think they would not expect this… it is the sort of thing you know about if you are somebody who goes online to talk about text editors I think). And these are also the sort of users who are used to seeing shebangs and other line noise at the top of files, not understanding it, and ignoring it.
I think we’re only being protected by the fact that spreading a virus though command-line text editors is… going to result in not a ton of hits.
I'm confused. Per the doc, it is disabled by default? Specifically, the first time it is encountered on a file, it will ask the user if they want to allow it. And they flat out don't ever do things like "eval" during these values.
That's a different potential vulnerability. I knew about that one (and had disabled the running of such scripts). I didn't know about this one till today.
Helping me finish typing the name of a function or variable ("completion") is not the sort of thing I expected (till today) the maintainers of Emacs to be so eager to do that they'd start running code that I never asked to be run.
A common pitfall of IDE integration for dynamic languages is that it tends to execute the code under test to provide contextual completion or may decide to run doctests, etc. This has been/is a problem with editing Ruby code, and perhaps Python code and more too too. I'm unsure if this is a problem editing vimscript or lua with NeoVim with the only non-evidence is that I haven't heard of it.
The Church of Vim is always accepting new disciples.
Jokes aside, if you're considering Vi-like editors (and assuming you haven't already done your research -- which by the sounds of it, you may well have):
- I recommend going for Neovim over classic Vim at this point. The first-class Lua support for building out your configs and working with extensions is a big quality-of-life improvement over just VimL, and it's a more portable skill with fewer surprises. As a bonus, this gives you access to a world of shockingly high-quality extensions that require Lua to run.
- If you want a decent starting point before you start tweaking a ton of settings, Spacevim is it. I haven't used it extensively but I've only heard good things.
- I recommend against trying to use Emacs bindings in Vim if you can help it. I used these when I initially moved over (at this point about a decade ago) and they were clunkier than both Emacs's bindings and Vim's native bindings. Learning how to work with Vim's modes is an investment that pays off as quickly as a few days with intense use, or a few weeks with more casual use.
- `vim-arpeggio` (or the native chording support in newer versions of Neovim) is your friend for avoiding `<Esc>`-induced repetitive-strain injury.
As a schismatic from the Church of Vim, I’m compelled to recommend kakoune here. Unless you’re running in a peculiar legacy platform like Windows or Amiga, the selection oriented editing and smooth Unix integration are a delight.
I've considered it from time to time. The conclusion I keep drawing is that, if I were going to benefit from a selection-oriented editing paradigm, I would use Visual mode more than I do.
The multi-cursors, those I want. But I'm willing to wait for Neovim to get them.
That’s entirely reasonable; I switched in part because I was using visual mode so much. That being said, if you want a more vi-like experience in kakoune, you can always pipe your whole buffer through sed :)
As another fan of Kakoune's model of editing (or model of modal editing), I would recommend Helix. It's a low-config tool that lets you start working without turning many knobs. Supports tree-sitter grammars and language server protocol.
> I recommend against trying to use Emacs bindings in Vim if you can help it
This is fine, I think. Using C-w is more convenient than <Esc>diw. I also find C-a and C-e quite convenient, although you need plugins for these (tpope's vim-rsi is good).
I might be worth starting without them, though, so they learn not to rely on them too much.
That being said, I use home-row mods, which makes Control a lot easier to use than regular keyboards.
Are you saying there can’t be security vulnerabilities in Neovim? [rhetorical question]
As I understand it, the vulnerability is that viewing untrusted elisp code may lead to arbitrary code execution. Personally, I don’t remember a case where I would view elisp code without the intent of running it.
The whole issue of trusting other peoples code does have a solution besides just not running it: capability based code execution ("Capability-based security" if you want to look it up)
Processes can forfeit the permission to do certain things. similarily you could allow functions to forfeit the permission to call certain functions down the callstack (transitively, even) or only allow a function to be called from certain contexts/functions.
While certainly a (minor) performance hit when done dynamically, it should be possible,
especially when using an interpreted language. I have not yet seen this done in the context of programming languages, which is probably due to how difficult it would be to set a proper scope and get it right. If A is forbidden from deleting files, for example, but the program allows it to send messages to B (perhaps even by user choice), which is allowed to do so, then that is a natural escape hatch unless B is specifically designed to take this into account. Nonetheless, a hybrid system should be possible to achive, which would at least improve the situation by a non-negligible margin.
In the spirit of the original article: Most editor plugins don't need to interact with other processes or the file system directly, and instead could only affect an associated buffer. In this scenario, I believe that it is actually possible to solve this issue. For other applications, such as git integration, the mass of code that would have to be inspected can at least be reduced.
For folks that have never poked around in emacs, the specific difficulty will be that the odds are very high that if you are in an emacs lisp file, you are almost certainly going to want to edit what emacs itself is doing.
I'm specifically talking about scenarios such as "you set debug-on-error."
To that end, the proposal would probably be something like "flymake/flycheck" use a child emacs process to query the code, but the user evaluating the code would still be done in the main emacs?
Wouldn't it be sufficient to "just" write a kind of context manager that watches the macro expansion and then looks at each step what's being done and divvies that up into safe and unsafe execution, so that at least the example of the article
doesn't just automatically run? Obviously it's a lot of work depending on how sophisticated you want that to be but you probably don't need to rearchitect much.
I feel like capability systems are... the right solution to the right problem at the wrong time.
By that I mean, in an ideal world, nefarious code should never end up on my system in the first place. Regardless of whether it gets ran, regardless if whether it is properly sandboxed to avoid damage. At the end of the day, I don't want bad code in my system at all.
"Easier said than done" is why I said "right solution, right problem, wrong time." But it comes at a cost. A rather extreme cost, in some cases. Walled garden app stores. Runtime overhead.
Development overhead. I'm not just a user, I'm also a developer, so these things end up being roadblocks I have to navigate. And I have to navigate them for no reason of my own. I am not trying to steal my users' data. But in a way, I am getting punished for the actions of others.
Scary. I saw a tweet the other day from a job seeker who had been sent a repo of seemingly trustworthy code. The sender claimed to be working with a team that was hiring, or something along those lines. Of course, one file deeply nested within the folds of the project contained a block of obfuscated JavaScript designed to grab as much data from the job seeker as possible and transmit it elsewhere. Had the job seeker run the project without reading through it first, they would have been in hot water.
You can imagine some variant of this attack including a carefully designed Emacs Lisp payload, which the unsuspecting and desperate-for-a-job victim might open in Emacs. Surprising that the Emacs maintainers didn't fix it as quickly as you'd hope.
Emacs doesn't market itself as a sandboxed tool. It is purpose built to give users unrivaled powers. There are obvious consequnces to this. What is more scary is running untrusted js in a browser that has been marketed as sanboxed, but you probably do this all day every day
While I'm trying to sober up people who are panicking I don't mean to downplay the dangers. The op article is quite informative and should be read by all emacs users. While malicious el code is probably rare, the value gained by compromising an emacs user (programmers academics researchers etc) compared to compromising a random js user (everyone) is probably way greater. Also very few people look at emacs security
This feels like a social problem instead of a technical one. Macros and macro expansion are a core language feature. Code analysis tools have to do macro expansion. You can't handicap core language features and tools in the name of safety. If you are doing something potentially dangerous, you just have to take precautions.
Real world analogy: construction sites are dangerous, but you can't outlaw the bulldozer. It is a necessary piece of equipment. The best you can do is take precautions. Hard hats, high visibility clothing, audible warnings, etc.
Largely this problem which is core to Emacs in the sense it literally is "An Elegant Weapon For A More Civilized Time" due to its age. There is no concept of sandboxing anything in Emacs. You do get an alert sometimes when you change Theme's since they have a notion of totally executable code. Maybe a better solution would be to make a subset of elisp that artifacts be coded in which are sandboxed.
Well yes, when "code is data", data suddenly becomes very dangerous. This is recurring theme when dealing with Lisps and Emacs especially. For instance, it is also quite common for Emacs packages to save data in the form of ELisp code. When loading the data, it is simply evaluated and boom, your data is loaded. It's a powerful thing, but of course this is a security issue, and this is why we can't have nice things...
It is (should be) well known that macros, lisp ones and even less capables ones from other languages, are problematic for security. I think a good temporary mitigation to this in Emacs is scanning 3rd party .el files for macros. If there is a macro present give trust warning and offer decreased functionality if untrusted
Macros are pretty ubiquitous in lisp. This would result in a trust warning for pretty much every .el file. I think this would go about as well as Windows Vista UAC pop ups or State of California cancer warnings. If everything is dangerous, nothing is.
If I understand this correctly, this exploit only works with macros that evaluate at least one of their arguments, otherwise no code is actually run. These kind of macros are not that common. I guess one possible fix would be to mark these kind of macros as potentially dangerous and do not expand them automatically for things like code completion and such.
The qualifying term is 'trusted'. If you are running an application like emacs you damn sure better trust it. It's like running Windows and saying you don't trust it.
AS for macros in lisp, they are not as ubiquitous as it might seem to an outsider. I write lisp professionally. I write one macro a month, if that, and often I rewrite it as a function afterwards. Saying that macros are ubiquitous in lisp is a meme. To most lispers macros are last resort
I'm obligated by tenants of my faith to point out that the best protection for this exploit is use of Vi(m) or NeoVim. You may throw tomatoes as soon as I duck behind this fence, thank you.
Best protection from exploits is to disconnect your computer, shut it down, smash it with a sledgehammer, quit your job and become a florist.
Whenever you folks say "just use Bla-bla instead of Emacs", you don't realize it's not even at the level of comparison between iOS and Android.
Emacs provides unique capabilities that other applications simply cannot match in terms of simplicity and power.
Like take for example Dired. Sure, there are number of vim plugins, but none of them match the full power of Emacs' Dired of treating directories as editable text.
Or take Org-mode's source blocks. You can for example execute a piece of javascript, then pipe the result into another block in python, then the results of that into sql and finally output it as a chart.
Or you can use source blocks for literate programming. I use them for managing my dotfiles - my entire system is almost immutable, not at the same level of Nix, but still very nice.
Or take an Emacs package called consult-omni - you can type a search query once and it dynamically dispatches queries to Google, YouTube, Wikipedia, your browser history and other places, aggregating the results in one place. Crazy thing is that the package builts on top of another package which itself uses the built-in functions of Emacs.
The power comes from ability to precisely change a behavior of any given function - built-in or a third party - that precision is just impossible in Vim, VSCode or IntelliJ - in Emacs, you can change specific point of any given function without having to rewrite it.
It's not a matter of "faith" as you put it. People who choose Emacs do that not because of some dogmas, beliefs or folklore. Emacs has earned its reputation as the most extensible software for sound technical reasons. Naturally, any powerful tool can be wielded for both constructive and destructive purposes.
Circa 2002-2003, and the LWN comment describing the exact same scope:
"""emacs is the same, if not worse. (See the node File Variables in the info docs.) You get not only to set random buffer-local variables, but also to evaluate arbitrary lisp code. Ouch!"""
I'm obligated as part of my faith to point out that nano has none of these issues, as I understand that Vim will still execute arbitrary code in some circumstances
you're kidding but as an evil-mode user my first thought was "okay, inspect untrusted elisp in vim before opening it in emacs, got it"
Thanks for downvoting! I'm not sure why that isn't a valid approach, but then, I've never understood why people have a competition between a text editor and a Lisp machine that has an implementation of that text editor in it
Sorry, I find it hard to care. You have to multiply the damage caused by the prior probability of the event occurring, and my prior of this happening is very very low. There are so many easier ways to attack people (e.g. poison a package in a language they use, or on MELPA for Emacs hackers) that I can't see this particular attack getting any use.
Security is basically a resource allocation problem. There are an infinity of attack vectors, so which ones should one be concerned about? Probably not this one.
As a former Emacs advocate, I only use Emacs for org-mode and magit these days.
These are still the finest stay-organized and Git UI modules I've ever seen, respectively, and are still enough to make sure I have Emacs on every system I use.
For coding, I've gone over to VS Code (and sometimes Jetbrains).
I did some FOSS hacking as a teenager a quarter-century ago, so learned Emacs, but then ultimately chose a career unrelated to software development. I still use Emacs for anything and everything text-related: email (Gnus), RSS feeds (elfeed), org-mode where I write up both personal TODOs and serious academic research. The keyboard-driven interface is powerful and now muscle-memory. The in-built Lisp environment makes everything nicely extensible, but Emacs as an IDE, as something people have used to create general software projects, is something I rarely think about.
Long time Emacs Lisp coder here. Here is a summary of the vulnerability described in the OP:
Anyone wishing to inspect an untrusted file of Emacs Lisp code is likely to use Emacs to do the inspecting, but if either of the popular packages Flymake and Flycheck is enabled, merely opening the untrusted file gives the author of the file the ability to run arbitrary code (because macros are tricky). Even if an Emacs user avoids Flymake and Flycheck, the standard emacs facility for "completing" the names of functions and variables has the same basic vulnerability. Specifically, if the user uses Emacs to open the file, then types the start of the name of a function or variable, then types M-tab (i.e., presses the escape key, then presses the tab key) which attempts to fill in the rest of the name so that user does not have to manually type out the whole name, the arbitrary code is run.
It is clear to me (who was never tempted to use Flymake or Flycheck) what remediation I want: namely I want this "M-tab" functionality (which I have been using and probably most Emacs users have been using) to refrain completely from expanding any macros even though doing so will prevent it from finding out the names of some of the functions and variables I might be trying to insert with the result that sometimes I will have to type out the full name of the function or variable, without assistance.
>AFAICT the earliest public discussion about the security implications of Emacs Lisp macros started in August 2018, when Wilfred Hughes noted that code completion can lead to arbitrary code execution via macro-expansion.
The fact that the maintainers have yet to fix this is one more sign added to a list of 5 or 6 other signs that make me want to migrate away from Emacs.
Giving the maintainers the benefit of the doubt, I think the optimal solution solution would require a lot of thought and work. While I have no doubt that Elisp is an environment especially ripe for these kinds of exploits, it's by no means unique to Emacs. Just look at VSCode's solution to this problem: https://code.visualstudio.com/docs/editor/workspace-trust .
I strongly prefer vscode's solution to the current state of affairs in Emacs.
I have no doubt that VSCode has a much less risk of executing code by opening something. Ironically however, it seems that VSCode's extension is the most effective channel to distribute malware in the history of code editors. [1] [2]
Not that MELPA couldn't be used to distribute malware either, I just think, as another poster mentioned, these problems are almost more social than technical.
[1] https://www.bleepingcomputer.com/news/security/malicious-vsc... [2] https://arxiv.org/html/2411.07479v1
Emacs is just too old to be architected with security in mind. It's a great editor, but has baggage that IMHO can't be addressed on the spot.
Working on a codebase where you can't (heavily?) break things between any commit imposes such a slow pace that it's not completely unreasonable to start from the ground up and just study what made Emacs great and what didn't work too well.
It's surprising how long Emacs has been around and how good of an editor it is. It really makes rewrite attempts such a long stretch that it exhausts the motivation and time out of spirited folks that give it a go, but I think that given how complexity is being modularised and moved out (LSP, DAP, grammars) and newer languages make packaging easier that Emacs will eventually be replaced, definitely without covering everything it can do, but being strong at the average editing session.
That's my opinion as well. I run Emacs 24/7 but I do so inside Firejail, with no network access. It's not architected with security in mind and exploits are too easy.
The same can be said about the Linux userland. The Unix model of giving plenty of access to resources and any user file to user processes is outdated.
I find it frustrating something like Firejail or bwrap is not standard. I don't want a compromised program to have easy access to e.g. my SSH keys.
>Emacs is just too old to be architected with security in mind.
Bad security is endemic to all GNU projects. gnutls and gnupg come readily to mind, for example. In fact there was an article/blog post making the rounds a few years ago about how the letters "GNU" are an excellent heuristic for broken security models and fatally-flawed crypto.
What about GnuTLS and GnuPG do you think makes them insecure? I think that they offer something unique and that must be factored in; i.e. if you compare them to competitors, you can't compare apples to oranges when making judgments for them. In mind I have projects like Open/Bear/Boring SSL to compare GnuTLS with, and sequoia for gpg. I really like sequoia, but it offers a different product to gnupg.
Emacs is a mosaic of 50 years of computer history, security is not its priority, but I guarantee you that in bug-gnu-emacs any security/network-related patches are most welcome.
Good call to prevent macro expansion. Does also no big harm nowadays as there are several other ways to get good auto completion, e.g. copilot. Other than that no need to restrict functionality for power users.
I'm a lot less worried about this than I am about MELPA packages being targeted. But any other editor that incorporates a package manager exposes the same threat surface, and just about all of them are a lot more popular (thus more worth targeting) than Emacs.
Yes, it boils down to "be careful with untrusted code" no matter where it comes from. This is certainly not unique to emacs.
I'm starting to get "return to notepad++" vibes from HN today.
It looks like adding a defcustom that would disable macro expansion, and basically any attempts to eval the code being edited, should not be a lot of work, or at least doable. Disable it in your config, get a nerfed-down but shields-up elisp editing mode.
Am I missing anything here? E.g. should I expect pieces of C code that handle completion in elisp mode?
Would you mind explaining how you could do this?
I expect that the entire mode is implemented in elisp-mode.el. It's based on lisp-data-mode, but I don't expect that to handle macros (should check though).
Looking at elisp-completion-at-point and likely deeper into elisp--completion-local-symbols, I'd try to find where macroxpansion occurs, and made it conditional. Same for the explicit emacs-lisp-macroexpand.
I would also search for `(eval ` in general and maybe put it under a buffer-local flag, too, so that you won't press C-x C-e or C-M-x and execute malicious code by mistake, when you know you're working on a piece of malicious code.
Maybe instead of a defcustom, it should rather be a minor elisp-paranoid-mode which would do all kinds of things to prevent execution of the code in the buffer, or the code the buffer refers to, etc.
Doesn’t vim also have some ability, easily abused, to put a script at the top of a file, and it’ll just run when you open the thing?
This seems like a really useful functionality to have in the context where you actually do trust the files, but it is wildly insecure and an unexpected trapdoor, to have simple files executing things when you open them with a simple text editor…
Emacs has that, too. There are protections in that case, though. See: https://www.gnu.org/software/emacs/manual/html_node/emacs/Sa...
Probably going to add similar protections here? Basically, I'd assume if it is your first time visiting a file, macros won't be expanded during autocompletion.
I dunno. I can see why this functionality might be useful, but I kinda think distros should disable it by default/make it whitelist-only.
I think the implications are really unexpected for “new” users (where “new” could be pretty generously defined, I mean, I know a couple people who use vim IRL, I think they would not expect this… it is the sort of thing you know about if you are somebody who goes online to talk about text editors I think). And these are also the sort of users who are used to seeing shebangs and other line noise at the top of files, not understanding it, and ignoring it.
I think we’re only being protected by the fact that spreading a virus though command-line text editors is… going to result in not a ton of hits.
I'm confused. Per the doc, it is disabled by default? Specifically, the first time it is encountered on a file, it will ask the user if they want to allow it. And they flat out don't ever do things like "eval" during these values.
That's a different potential vulnerability. I knew about that one (and had disabled the running of such scripts). I didn't know about this one till today.
Helping me finish typing the name of a function or variable ("completion") is not the sort of thing I expected (till today) the maintainers of Emacs to be so eager to do that they'd start running code that I never asked to be run.
A common pitfall of IDE integration for dynamic languages is that it tends to execute the code under test to provide contextual completion or may decide to run doctests, etc. This has been/is a problem with editing Ruby code, and perhaps Python code and more too too. I'm unsure if this is a problem editing vimscript or lua with NeoVim with the only non-evidence is that I haven't heard of it.
You could also macroexpand in a sandbox, e.g. via LSP.
That would involve a rewrite because the way it is now, the relevant code does not use LSP.
Okay, but software is infinitely malleable
What are the other 5, out of curiosity?
The Church of Vim is always accepting new disciples.
Jokes aside, if you're considering Vi-like editors (and assuming you haven't already done your research -- which by the sounds of it, you may well have):
- I recommend going for Neovim over classic Vim at this point. The first-class Lua support for building out your configs and working with extensions is a big quality-of-life improvement over just VimL, and it's a more portable skill with fewer surprises. As a bonus, this gives you access to a world of shockingly high-quality extensions that require Lua to run.
- If you want a decent starting point before you start tweaking a ton of settings, Spacevim is it. I haven't used it extensively but I've only heard good things.
- I recommend against trying to use Emacs bindings in Vim if you can help it. I used these when I initially moved over (at this point about a decade ago) and they were clunkier than both Emacs's bindings and Vim's native bindings. Learning how to work with Vim's modes is an investment that pays off as quickly as a few days with intense use, or a few weeks with more casual use.
- `vim-arpeggio` (or the native chording support in newer versions of Neovim) is your friend for avoiding `<Esc>`-induced repetitive-strain injury.
As a schismatic from the Church of Vim, I’m compelled to recommend kakoune here. Unless you’re running in a peculiar legacy platform like Windows or Amiga, the selection oriented editing and smooth Unix integration are a delight.
I've considered it from time to time. The conclusion I keep drawing is that, if I were going to benefit from a selection-oriented editing paradigm, I would use Visual mode more than I do.
The multi-cursors, those I want. But I'm willing to wait for Neovim to get them.
That’s entirely reasonable; I switched in part because I was using visual mode so much. That being said, if you want a more vi-like experience in kakoune, you can always pipe your whole buffer through sed :)
As another fan of Kakoune's model of editing (or model of modal editing), I would recommend Helix. It's a low-config tool that lets you start working without turning many knobs. Supports tree-sitter grammars and language server protocol.
I haven't heard of either Kakoune or Helix, but I'm buried pretty deep in my own opinionated config.
As far as I'm concerned, the more readymade options, the better. Thanks to you and sevensor for adding recommendations!
> I recommend against trying to use Emacs bindings in Vim if you can help it
This is fine, I think. Using C-w is more convenient than <Esc>diw. I also find C-a and C-e quite convenient, although you need plugins for these (tpope's vim-rsi is good).
I might be worth starting without them, though, so they learn not to rely on them too much.
That being said, I use home-row mods, which makes Control a lot easier to use than regular keyboards.
Spacevim? Emacs bindings in vim? Heresy!
Spacemacs defaults to vim bindings and it's easily my favorite editor, while saving you from (some of) the endless config tweaking.
Are you saying there can’t be security vulnerabilities in Neovim? [rhetorical question]
As I understand it, the vulnerability is that viewing untrusted elisp code may lead to arbitrary code execution. Personally, I don’t remember a case where I would view elisp code without the intent of running it.
The whole issue of trusting other peoples code does have a solution besides just not running it: capability based code execution ("Capability-based security" if you want to look it up)
Processes can forfeit the permission to do certain things. similarily you could allow functions to forfeit the permission to call certain functions down the callstack (transitively, even) or only allow a function to be called from certain contexts/functions.
While certainly a (minor) performance hit when done dynamically, it should be possible, especially when using an interpreted language. I have not yet seen this done in the context of programming languages, which is probably due to how difficult it would be to set a proper scope and get it right. If A is forbidden from deleting files, for example, but the program allows it to send messages to B (perhaps even by user choice), which is allowed to do so, then that is a natural escape hatch unless B is specifically designed to take this into account. Nonetheless, a hybrid system should be possible to achive, which would at least improve the situation by a non-negligible margin.
In the spirit of the original article: Most editor plugins don't need to interact with other processes or the file system directly, and instead could only affect an associated buffer. In this scenario, I believe that it is actually possible to solve this issue. For other applications, such as git integration, the mass of code that would have to be inspected can at least be reduced.
The problem here is that Emacs is the Elisp interpreter. They are the same thing.
Emacs would have to start another process for Elisp analysis and code completion. That would be a massive reachitecture of the system.
For folks that have never poked around in emacs, the specific difficulty will be that the odds are very high that if you are in an emacs lisp file, you are almost certainly going to want to edit what emacs itself is doing.
I'm specifically talking about scenarios such as "you set debug-on-error."
To that end, the proposal would probably be something like "flymake/flycheck" use a child emacs process to query the code, but the user evaluating the code would still be done in the main emacs?
Wouldn't it be sufficient to "just" write a kind of context manager that watches the macro expansion and then looks at each step what's being done and divvies that up into safe and unsafe execution, so that at least the example of the article
doesn't just automatically run? Obviously it's a lot of work depending on how sophisticated you want that to be but you probably don't need to rearchitect much.I feel like capability systems are... the right solution to the right problem at the wrong time.
By that I mean, in an ideal world, nefarious code should never end up on my system in the first place. Regardless of whether it gets ran, regardless if whether it is properly sandboxed to avoid damage. At the end of the day, I don't want bad code in my system at all.
"Easier said than done" is why I said "right solution, right problem, wrong time." But it comes at a cost. A rather extreme cost, in some cases. Walled garden app stores. Runtime overhead.
Development overhead. I'm not just a user, I'm also a developer, so these things end up being roadblocks I have to navigate. And I have to navigate them for no reason of my own. I am not trying to steal my users' data. But in a way, I am getting punished for the actions of others.
Anyway. No solutions here.
Scary. I saw a tweet the other day from a job seeker who had been sent a repo of seemingly trustworthy code. The sender claimed to be working with a team that was hiring, or something along those lines. Of course, one file deeply nested within the folds of the project contained a block of obfuscated JavaScript designed to grab as much data from the job seeker as possible and transmit it elsewhere. Had the job seeker run the project without reading through it first, they would have been in hot water.
You can imagine some variant of this attack including a carefully designed Emacs Lisp payload, which the unsuspecting and desperate-for-a-job victim might open in Emacs. Surprising that the Emacs maintainers didn't fix it as quickly as you'd hope.
Emacs doesn't market itself as a sandboxed tool. It is purpose built to give users unrivaled powers. There are obvious consequnces to this. What is more scary is running untrusted js in a browser that has been marketed as sanboxed, but you probably do this all day every day
Agreed. Also, I expect that malicious elisp is relatively rare, while malicious js is probably about half of it.
While I'm trying to sober up people who are panicking I don't mean to downplay the dangers. The op article is quite informative and should be read by all emacs users. While malicious el code is probably rare, the value gained by compromising an emacs user (programmers academics researchers etc) compared to compromising a random js user (everyone) is probably way greater. Also very few people look at emacs security
This feels like a social problem instead of a technical one. Macros and macro expansion are a core language feature. Code analysis tools have to do macro expansion. You can't handicap core language features and tools in the name of safety. If you are doing something potentially dangerous, you just have to take precautions.
Real world analogy: construction sites are dangerous, but you can't outlaw the bulldozer. It is a necessary piece of equipment. The best you can do is take precautions. Hard hats, high visibility clothing, audible warnings, etc.
Largely this problem which is core to Emacs in the sense it literally is "An Elegant Weapon For A More Civilized Time" due to its age. There is no concept of sandboxing anything in Emacs. You do get an alert sometimes when you change Theme's since they have a notion of totally executable code. Maybe a better solution would be to make a subset of elisp that artifacts be coded in which are sandboxed.
No sandboxing is not a bug, it is the feature that makes emacs into elisp platform, and not just another editor that has defined API for extensions.
This problem is specific to elisp evaluation. It is rare that you would want to work in elisp code and not be modifying your currently running emacs.
If you are working on code for any other language, it is probably using an LSP or other form of child processes, right?
Well I wouldn't say any other language. Common Lisp for example you have a currently running lisp instance that you are modifying.
You can pretty easily set up Emacs to work that way for any language with a REPL.
Bulldozers also come with keys that stop random people walking up and turning them on though
And a big enough plane does not stop random people from walking up and turning them on. I don't think this analogy fits here.
I've been very very reluctant to install third-party extensions to Jetbrains, VScode, and Emacs for just this sort of problem. And it sucks.
Well yes, when "code is data", data suddenly becomes very dangerous. This is recurring theme when dealing with Lisps and Emacs especially. For instance, it is also quite common for Emacs packages to save data in the form of ELisp code. When loading the data, it is simply evaluated and boom, your data is loaded. It's a powerful thing, but of course this is a security issue, and this is why we can't have nice things...
How would this work?
I get no printout when doing C-M-i with the cursor after "mac".Edit: OK. As per the mailing list. I guess it is a feature then.
I consider this a feature and I know how to avoid the fix so thanks for the heads up.
Various modes already prompt if one wishes to respect file-local settings; I imagine that the fix here is similar.
It is (should be) well known that macros, lisp ones and even less capables ones from other languages, are problematic for security. I think a good temporary mitigation to this in Emacs is scanning 3rd party .el files for macros. If there is a macro present give trust warning and offer decreased functionality if untrusted
Macros are pretty ubiquitous in lisp. This would result in a trust warning for pretty much every .el file. I think this would go about as well as Windows Vista UAC pop ups or State of California cancer warnings. If everything is dangerous, nothing is.
If I understand this correctly, this exploit only works with macros that evaluate at least one of their arguments, otherwise no code is actually run. These kind of macros are not that common. I guess one possible fix would be to mark these kind of macros as potentially dangerous and do not expand them automatically for things like code completion and such.
The qualifying term is 'trusted'. If you are running an application like emacs you damn sure better trust it. It's like running Windows and saying you don't trust it.
AS for macros in lisp, they are not as ubiquitous as it might seem to an outsider. I write lisp professionally. I write one macro a month, if that, and often I rewrite it as a function afterwards. Saying that macros are ubiquitous in lisp is a meme. To most lispers macros are last resort
This is what Word and Excel (used to?) do when opening (or was it previewing?) .doc and .xls files in email. Macros, if present, were disabled.
I'm obligated by tenants of my faith to point out that the best protection for this exploit is use of Vi(m) or NeoVim. You may throw tomatoes as soon as I duck behind this fence, thank you.
Best protection from exploits is to disconnect your computer, shut it down, smash it with a sledgehammer, quit your job and become a florist.
Whenever you folks say "just use Bla-bla instead of Emacs", you don't realize it's not even at the level of comparison between iOS and Android.
Emacs provides unique capabilities that other applications simply cannot match in terms of simplicity and power.
Like take for example Dired. Sure, there are number of vim plugins, but none of them match the full power of Emacs' Dired of treating directories as editable text.
Or take Org-mode's source blocks. You can for example execute a piece of javascript, then pipe the result into another block in python, then the results of that into sql and finally output it as a chart.
Or you can use source blocks for literate programming. I use them for managing my dotfiles - my entire system is almost immutable, not at the same level of Nix, but still very nice.
Or take an Emacs package called consult-omni - you can type a search query once and it dynamically dispatches queries to Google, YouTube, Wikipedia, your browser history and other places, aggregating the results in one place. Crazy thing is that the package builts on top of another package which itself uses the built-in functions of Emacs.
The power comes from ability to precisely change a behavior of any given function - built-in or a third party - that precision is just impossible in Vim, VSCode or IntelliJ - in Emacs, you can change specific point of any given function without having to rewrite it.
It's not a matter of "faith" as you put it. People who choose Emacs do that not because of some dogmas, beliefs or folklore. Emacs has earned its reputation as the most extensible software for sound technical reasons. Naturally, any powerful tool can be wielded for both constructive and destructive purposes.
vim used to have similar vulnerabilities (maybe still does?) via modelines:
https://security.stackexchange.com/questions/36001/vim-model...
https://lwn.net/Articles/20249/
Circa 2002-2003, and the LWN comment describing the exact same scope:
"""emacs is the same, if not worse. (See the node File Variables in the info docs.) You get not only to set random buffer-local variables, but also to evaluate arbitrary lisp code. Ouch!"""
Someone took the first tomato!
I'm firmly in the vim camp, just wanting to share the history, utterly surprised (but not...) that it's ~25+ years in the making.
Funny story once checking a bug report, OG founder of the company dropped in: "I like to check in on my bug reports every 10 years..."
It's not just an open-source issue, hard decisions are hard decisions.
The as a fellow renter of your faith, I’m are worried that somebody playing with the “modeline” option might burn down the place.
I'm obligated as part of my faith to point out that nano has none of these issues, as I understand that Vim will still execute arbitrary code in some circumstances
I believe I nothing, but even I know that ed is the standard editor.
Of course it does except vim users have no idea how to read vim code so they wouldnt even know
"Tenets" of your faith. "Tenants" means that you are leasing out space in your faith to other people.
Wasn't the protestant reformation more or less about the tenants of that faith not wanting to pay rent anymore?
"tenants" clearly being the superior option
Downvoted and flagged!
you're kidding but as an evil-mode user my first thought was "okay, inspect untrusted elisp in vim before opening it in emacs, got it"
Thanks for downvoting! I'm not sure why that isn't a valid approach, but then, I've never understood why people have a competition between a text editor and a Lisp machine that has an implementation of that text editor in it
And vice-versa. Brilliant!
Step one: use vi Step two: there is no step two.
Ed is the standard editor.
?
Sorry, I find it hard to care. You have to multiply the damage caused by the prior probability of the event occurring, and my prior of this happening is very very low. There are so many easier ways to attack people (e.g. poison a package in a language they use, or on MELPA for Emacs hackers) that I can't see this particular attack getting any use.
Security is basically a resource allocation problem. There are an infinity of attack vectors, so which ones should one be concerned about? Probably not this one.
As a former Emacs advocate, I only use Emacs for org-mode and magit these days.
These are still the finest stay-organized and Git UI modules I've ever seen, respectively, and are still enough to make sure I have Emacs on every system I use.
For coding, I've gone over to VS Code (and sometimes Jetbrains).
I did some FOSS hacking as a teenager a quarter-century ago, so learned Emacs, but then ultimately chose a career unrelated to software development. I still use Emacs for anything and everything text-related: email (Gnus), RSS feeds (elfeed), org-mode where I write up both personal TODOs and serious academic research. The keyboard-driven interface is powerful and now muscle-memory. The in-built Lisp environment makes everything nicely extensible, but Emacs as an IDE, as something people have used to create general software projects, is something I rarely think about.
You use VSCode for coding, and Emacs for org and magit. What do you use for everything else? :-)
As a sibling comment pointed out, many, if not most, long term heavy Emacs users are not using it for coding.