As I understand it, this is talking about an SSH server built into Erlang/OTP, not e.g. OpenSSH on a server with Erlang installed.
>Any service using Erlang/OTP's SSH library for remote access such as those used in OT/IoT devices, edge computing devices are susceptible to exploitation.
Erlang, because of its architecture, has something of a habit of people rewriting various protocols in Erlang itself, rather than calling out to some C library.
Writing protocol code in Erlang is nice, because the parsing is so easy and clear. And if you want to do something that's not so easy by spawning a command, then you may as well build it in Erlang. And it's fun and symmetric to build both a server and a client... I've not looked at OTP SSH code, but I'd assume the ciphering is still calls to external c libraries, as it is in the OTP TLS code.
Of course, easy protocol parsing doesn't do the whole job; state management is required too (and was missed here, clearly).
This is probably because C NIFs run in the same process as the Erlang scheduler. If you have a long-running or blocking NIF, it can starve the scheduler and cause significant performance degradation across the system.
yes, but there is a finite number of them, by default equal to the number of available cores. If your connection stays in c-land for too long you might run into trouble, if more than one connection are desired.
libuv is more or less abstraction around an event loop for async i/o right?
The BEAM is also more or less an abstraction around an event loop for async i/o. If you want async i/o in nifs, I think you want to integrate with BEAM's event loop. Inside NIFs, I think you want to use enif_select [1] (and friends), available since OTP 20 originally from 2017-06-21. In a port driver, you'd use driver_select [2] which I think has been around forever --- there's mentions of changes in R13 which I think was mostly release 2009-11-20 (that may have been R13B though).
It uses different threads in order to make infrequent blocking calls look like they are asynchronous.
When we (or at least some quantity of “we”) want is infrequent native calls to be able to fail without taking the BEAM down.
The problem with doing it with threads though is that a bad thread can still vomit all over working memory, still causing a panic even if it itself doesn’t panic.
Oh I see. If you need to isolate your native code from your BEAM, then you've got several options.
a) run the native code as a separate process; either a port program, a c-node, or just a regular program that you interact with via some interprocess communication (sockets, pipes, signals, a shared filesystem, shared memory segments if you're brave)
b) some sort of sandybox thing; like compile to wasm and then jit back to (hopefully) safe native.
c) just run the native code, it's probably fine, hopefully. My experience with NIFs is that they are usually very short code that should be easy to review, so this isn't as bad as it sounds...
If your native code is short, option c is probably fine; if your native code is long, option a makes more sense. If you want to make things harder without real justification, b sounds good :P
I suspect the confusion of priorities comes from running native code that’s time consuming and wanting it to horizontally scale with your cluster, which is easier if you try to let the beam do it.
While what is easier for those of us not working on the beam is to put the glitchy code into its own service and put up with the maintenance overhead.
But when you have one or two solutions the friction to move to three becomes difficult. People start talking about how having dozens will be chaos. While true, sometimes you really do just need three and it’s not a slippery slope.
This is why I generally do not rely on SSH servers other than OpenSSH. It's (by far) the most widely deployed implementation, thoroughly battle-tested, etc. It's also hard to actually get pwned; the OpenBSD[1] guys believe in security as the default.
There's some value in avoiding a monoculture, or choosing different trade-offs (e.g. binary size, memory usage). But as exemplified by this incident, any incentives must be carefully weighted against the risks. SSH is your final line of defence.
There's a huge difference here, historically that was because many C codebases were vulnerable due to inherent C flaws and ssh daemons due to their age was C based. OpenBSD folks stances on coding and system design avoids pitfalls.
This is an Erlang daemon, thus written in a managed language without buffer overflows,etc, but it seems like someone left a huge gaping logic hole to drive a bus through. SSH or not, this could've equally well been a logic hole in a base webserver,etc.
I'd say this is more akin to the Log4j debacle, a perfectly safe language but bad design makes it vulnerable to something trivial.
It's true that there are 5 advisories so far in this year alone, but let's consider the actual impact:
CVE-2025-32728 - Error in documentation, possibly leading to misconfiguration
CVE-2025-30095 - Debian+dropbear-specific
CVE-2025-27731 - Windows-specific; local privilege escalation; OpenSSH doesn't target/support Windows
CVE-2025-26466 - Remote DoS
CVE-2025-26465 - MitM involving host key DNS verification; high attack complexity (relies on exhausting client memory)
OpenBSD enables sshd(8) in the default install, and has so far had two RCEs in 30 years. Now, not everyone runs OpenBSD, but I'd personally throw the stones at e.g. Debian (see CVE-2008-0166).
I'm a big fan of Erlang, but I don't think this is a fair thing to praise.
Only OpenSSL had heartbleed. No other implementation of TLS protocols was affected. Many systems integrate with OpenSSL's protocol code, but there's also several that do their own protocol work and use ciphers from OpenSSL (and some that do both).
Erlang's ssl implementation at the time of heartbleed wasn't anywhere close in throughput to using OpenSSL separately. If I'm remembering right, OTP 18 (June 2015) is when it got good enough that it made more sense to run an Erlang https server without a separate TLS termination daemon. Heartbleed became known April 2014, so Erlang SSL was too late to help there, really. More secure, but unusable wirh load doesn't help much.
Also, Erlang SSL was one of many implementations thst needed to be reminded of 1998 era security issues in 2017. [1]
I'm assuming the most likely affected Elixir projects would be those using Nerves with SSH enabled and exposed to the public internet, as nerves_ssh wraps the OTP SSH daemon.
Don't think that's a very common thing to do, even in my hobby projects I would only access a Nerves device through a VPN.
This is also true of erlang right? This module is part of the stdlib but if you haven't implemented access using it it's "turned off" in the same way any other libraries you aren't using are.
How does this affect servers like ejabberd? I just noticed that they upgraded their server yesterday [0] and am wondering if it could contain some kind of fix for this, or would this be unrelated?
ejabberd doesn't start the Erlang SSH daemon; or at least codesearch on their github doesn't have any reference to ssh other than something unrelated trying to figure out if a url is a git repo.
I didn't think anyone actually ran the Erlang SSH daemon (although there's evidence that some people do!). It makes for a fun demo, but a regular OS shell is more useful, and you can attach a debug shell to an existing BEAM process from there.
> It makes for a fun demo, but a regular OS shell is more useful, and you can attach a debug shell to an existing BEAM process from there.
OTOH for example in Go people sometimes use the SSH protocol to provide access to cool things like an SSH based chat, instead of using it for shell access.
I haven’t looked at what the Erlang SSH server provides, but maybe you could do something like that? Write a chat server in Erlang and use the Erlang SSH server to provide users access to that chat?
Yes, the Erlang debug shell is just the default option; you can replace the interface with whatever, if you wanted to build a chat/mud/ascii cinema/etc, it should all be possible (but you'd be advised to review the OTP ssh code to confirm it does what you want and nothing extra)
Oops..... we are currently trying to sell an elixir-based greenfield project internally. This doesn't affect elixir by default as other commenters pointed out, but still might make our project a bit harder to pitch to management...
If your organization is looking for "the language ecosystem that never has any security vulnerabilities", pack it in and close up shop because you're not going to find one. How many, how often, and how they are handled is far more important.
While the Erlang/Elixir ecosystem won't stop you from writing a network server that takes in a string and just blithely passes it along to a shell without analysis, overall the Erlang/Elixir ecosystem is very strong and lacks most of the footguns like an "eval" statement that get people. Though I will ding it a point for the most obvious way to run a shell command [1] taking just a string that goes to a shell rather than an array of parameters to a shell command.
It is on the higher end of secure languages to write a network server in.
> overall the Erlang/Elixir ecosystem is very strong and lacks most of the footguns like an "eval" statement that get people
Erlang has erl_eval [1] if you're looking for more ability to shoot yourself in the foot. You can call that from Elixir, but I guess that'd be weird; I'm not an Elixir person, but I'd bet you can shoot yourself in the foot if you try!
There's always fun with dist and proc_lib:spawn(Node, Fun) [2], which you can put in a list comprehension with erlang:nodes() [3] if you want to shot yourself in many feet rapidly ;)
All this foot shooting - this is the problem with permissive gun laws. We should ideally lock down all firearms to prevent any civilian doing harm. Only the select few government agents should own firearms.
I’ve seen more horrendous code using macros in elixir even despite by brief foray than I have seen ever in decades of working in languages with eval. Like using them when normal functions would suffice.
Using macros when a function would do is a legit anti-pattern (and documented as such [1]) but unrelated to the security aspect as they are compile-time constructs.
The reason they were added to the language was precisely so meta and dynamic programming is done at compile time, which you can introspect before you deploy, versus doing it at runtime, which is how most dynamic languages tackle this. And those languages are most likely not using eval either, but intrinsic features that allow you to define classes, attributes, methods, and so on programmatically.
I’d say eval is discouraged in most languages, although it is useful for building things like REPLs and interactive environments.
That is quite the wrong way of looking at it. The vulnerability is in a implementation of SSH and not with the language/runtime itself; And it has already been patched. Erlang is a "managed" language and is quite secure compared to others.
You should definitely "sell" Elixir/Erlang/BEAM based languages to your management for a greenfield project; The opportunity is too good to pass up.
Nevertheless, if you would like to learn how to "harden" your Elixir/Erlang system, see the guidelines from the "Security Working Group" of EEF which i have linked to here - https://news.ycombinator.com/item?id=43717633
If I interpret the patch correctly the issue seems to be that you could just ask for a channel and do a request_exec before authenticating. The regression test is:
I'm vaguely surprised that https://www.runzero.com/sshamble/ didn't find this. They did a scan over the entire internet trying invalid SSH state machine transitions, which I guess didn't cover this sequence.
I was too! The reason is that the Go x/crypto/ssh library was bailing out on the lack of reply to the channel open request, which prevented it from reaching the auth bypass check via exec. I should have an update out soon with this fixed and a RCE check for this issue.
The test server: $ erl -eval 'ssh:start(), ssh_dbg:on(), ssh:daemon(34222, [{system_dir, "/home/otp/ssh/keys"},{user_dir, "/home/otp/ssh/users/otptest/.ssh"}]).'
The exploit: auth.ScrapeExec(options, addr+" "+tname, res, ses, `os:cmd("touch /tmp/HAXXXED").`)
CWE-306, Missing Authentication for Critical Function, linked in the report seems to suggest the same. The score of 10.0 is damn spicy, too - you just ask the server to execute something for you, and it does so, no questions asked.
Design bug here: Clearly we need to run code as somebody, so, there's no reason to have infrastructure which just executes user code with the current context or server (presumably? or maybe an actual zero, ie root) context.
If we design the software this way, when we try to write the erroneous code we're caught - oh, wait, which user is authenticated? We need to... oh... we shouldn't be here without authenticating.
Afaik, if you were running the Erlang SSH daemon, when you connect as an authorized user (or just ask!), it drops you into the Erlang debug shell. There's no concept of different users in the debug shell. Erlang dist is kind of an almost single system image cluster, with no security boundaries once you're connected to the cluster. (Well, not exactly no boundaries, you can mark a process sensitive, and ets tables private, and do some other things to make introspection difficult [1], but you can likely still spawn an os process debugger and get to everything; you would need to modify the OTP sources to disable os process spawning)
I didn't think anybody would actually run the Erlang SSH daemon, but there's evidence that some do. It makes more sense to run openssh, so you can debug BEAM failures etc, and you can load a debug shell from your OS shell easily.
> The issue is caused by a
flaw in the SSH protocol message handling which allows an attacker to
send connection protocol messages prior to authentication.
For folks interested in the Security aspects of Erlang/BEAM languages the guidelines from Security Working Group of the Erlang Ecosystem Foundation are a good resource - https://security.erlef.org/ and https://erlef.org/wg/security
As I understand it, this is talking about an SSH server built into Erlang/OTP, not e.g. OpenSSH on a server with Erlang installed.
>Any service using Erlang/OTP's SSH library for remote access such as those used in OT/IoT devices, edge computing devices are susceptible to exploitation.
https://thehackernews.com/2025/04/critical-erlangotp-ssh-vul...
Yes - one of the many things that you can find in OTP is a programmable SSH/SCP client and server. The vulnerability is in the server component.
See for example https://blog.differentpla.net/blog/2022/11/01/erlang-ssh/
Erlang, because of its architecture, has something of a habit of people rewriting various protocols in Erlang itself, rather than calling out to some C library.
This has pros and cons.
Writing protocol code in Erlang is nice, because the parsing is so easy and clear. And if you want to do something that's not so easy by spawning a command, then you may as well build it in Erlang. And it's fun and symmetric to build both a server and a client... I've not looked at OTP SSH code, but I'd assume the ciphering is still calls to external c libraries, as it is in the OTP TLS code.
Of course, easy protocol parsing doesn't do the whole job; state management is required too (and was missed here, clearly).
This is probably because C NIFs run in the same process as the Erlang scheduler. If you have a long-running or blocking NIF, it can starve the scheduler and cause significant performance degradation across the system.
I think they now have "dirty" NIFs that use a separate scheduler for this.
yes, but there is a finite number of them, by default equal to the number of available cores. If your connection stays in c-land for too long you might run into trouble, if more than one connection are desired.
I wonder if there's space for a libuv inspired solution now.
libuv is more or less abstraction around an event loop for async i/o right?
The BEAM is also more or less an abstraction around an event loop for async i/o. If you want async i/o in nifs, I think you want to integrate with BEAM's event loop. Inside NIFs, I think you want to use enif_select [1] (and friends), available since OTP 20 originally from 2017-06-21. In a port driver, you'd use driver_select [2] which I think has been around forever --- there's mentions of changes in R13 which I think was mostly release 2009-11-20 (that may have been R13B though).
[1] https://www.erlang.org/doc/apps/erts/erl_nif.html#enif_selec...
[2] https://www.erlang.org/doc/apps/erts/erl_driver.html#driver_...
It uses different threads in order to make infrequent blocking calls look like they are asynchronous.
When we (or at least some quantity of “we”) want is infrequent native calls to be able to fail without taking the BEAM down.
The problem with doing it with threads though is that a bad thread can still vomit all over working memory, still causing a panic even if it itself doesn’t panic.
Oh I see. If you need to isolate your native code from your BEAM, then you've got several options.
a) run the native code as a separate process; either a port program, a c-node, or just a regular program that you interact with via some interprocess communication (sockets, pipes, signals, a shared filesystem, shared memory segments if you're brave)
b) some sort of sandybox thing; like compile to wasm and then jit back to (hopefully) safe native.
c) just run the native code, it's probably fine, hopefully. My experience with NIFs is that they are usually very short code that should be easy to review, so this isn't as bad as it sounds...
If your native code is short, option c is probably fine; if your native code is long, option a makes more sense. If you want to make things harder without real justification, b sounds good :P
I suspect the confusion of priorities comes from running native code that’s time consuming and wanting it to horizontally scale with your cluster, which is easier if you try to let the beam do it.
While what is easier for those of us not working on the beam is to put the glitchy code into its own service and put up with the maintenance overhead.
But when you have one or two solutions the friction to move to three becomes difficult. People start talking about how having dozens will be chaos. While true, sometimes you really do just need three and it’s not a slippery slope.
> sometimes you really do just need three
If it's worth doing, it's worth doing three times.
This is why I generally do not rely on SSH servers other than OpenSSH. It's (by far) the most widely deployed implementation, thoroughly battle-tested, etc. It's also hard to actually get pwned; the OpenBSD[1] guys believe in security as the default.
There's some value in avoiding a monoculture, or choosing different trade-offs (e.g. binary size, memory usage). But as exemplified by this incident, any incentives must be carefully weighted against the risks. SSH is your final line of defence.
[1]: https://www.openbsd.org/donations.html
There's a huge difference here, historically that was because many C codebases were vulnerable due to inherent C flaws and ssh daemons due to their age was C based. OpenBSD folks stances on coding and system design avoids pitfalls.
This is an Erlang daemon, thus written in a managed language without buffer overflows,etc, but it seems like someone left a huge gaping logic hole to drive a bus through. SSH or not, this could've equally well been a logic hole in a base webserver,etc.
I'd say this is more akin to the Log4j debacle, a perfectly safe language but bad design makes it vulnerable to something trivial.
I also have this principle, although I make an exception for https://tinyssh.org
OpenSSH has actually been "pwned" numerous times though. It's a very desirable target.
I think in case of any security-critical project it's important to evaluate the track record objectively:
https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=OpenSSH
It's true that there are 5 advisories so far in this year alone, but let's consider the actual impact:
OpenBSD enables sshd(8) in the default install, and has so far had two RCEs in 30 years. Now, not everyone runs OpenBSD, but I'd personally throw the stones at e.g. Debian (see CVE-2008-0166).yeah and iirc erlang's ssl was one of the only ssl implementations not affected by heaetbleed since erlang is memory safe
I'm a big fan of Erlang, but I don't think this is a fair thing to praise.
Only OpenSSL had heartbleed. No other implementation of TLS protocols was affected. Many systems integrate with OpenSSL's protocol code, but there's also several that do their own protocol work and use ciphers from OpenSSL (and some that do both).
Erlang's ssl implementation at the time of heartbleed wasn't anywhere close in throughput to using OpenSSL separately. If I'm remembering right, OTP 18 (June 2015) is when it got good enough that it made more sense to run an Erlang https server without a separate TLS termination daemon. Heartbleed became known April 2014, so Erlang SSL was too late to help there, really. More secure, but unusable wirh load doesn't help much.
Also, Erlang SSL was one of many implementations thst needed to be reminded of 1998 era security issues in 2017. [1]
[1] https://nvd.nist.gov/vuln/detail/CVE-2017-1000385
most Elixir deployments are probably unaffected (obviously, please please check to be sure), as SSH is turned off by default.
https://paraxial.io/blog/erlang-ssh
I'm assuming the most likely affected Elixir projects would be those using Nerves with SSH enabled and exposed to the public internet, as nerves_ssh wraps the OTP SSH daemon.
Don't think that's a very common thing to do, even in my hobby projects I would only access a Nerves device through a VPN.
This is also true of erlang right? This module is part of the stdlib but if you haven't implemented access using it it's "turned off" in the same way any other libraries you aren't using are.
I wrote a GitHub „clone“ a while ago. Implementing Git’s wire and transfer protocol directly in Elixir.
https://git-scm.com/docs/protocol-v2
https://git-scm.com/book/ms/v2/Git-on-the-Server-The-Protoco...
Adding support for Git over SSH was very easy using Erlang built-in SSH libs.
https://github.com/redrabbit/git.limo
https://github.com/redrabbit/git.limo/blob/master/apps/gitgu...
How does this affect servers like ejabberd? I just noticed that they upgraded their server yesterday [0] and am wondering if it could contain some kind of fix for this, or would this be unrelated?
[0] https://github.com/processone/ejabberd/releases
ejabberd doesn't start the Erlang SSH daemon; or at least codesearch on their github doesn't have any reference to ssh other than something unrelated trying to figure out if a url is a git repo.
I didn't think anyone actually ran the Erlang SSH daemon (although there's evidence that some people do!). It makes for a fun demo, but a regular OS shell is more useful, and you can attach a debug shell to an existing BEAM process from there.
> It makes for a fun demo, but a regular OS shell is more useful, and you can attach a debug shell to an existing BEAM process from there.
OTOH for example in Go people sometimes use the SSH protocol to provide access to cool things like an SSH based chat, instead of using it for shell access.
I haven’t looked at what the Erlang SSH server provides, but maybe you could do something like that? Write a chat server in Erlang and use the Erlang SSH server to provide users access to that chat?
Yes, the Erlang debug shell is just the default option; you can replace the interface with whatever, if you wanted to build a chat/mud/ascii cinema/etc, it should all be possible (but you'd be advised to review the OTP ssh code to confirm it does what you want and nothing extra)
Oops..... we are currently trying to sell an elixir-based greenfield project internally. This doesn't affect elixir by default as other commenters pointed out, but still might make our project a bit harder to pitch to management...
If your organization is looking for "the language ecosystem that never has any security vulnerabilities", pack it in and close up shop because you're not going to find one. How many, how often, and how they are handled is far more important.
While the Erlang/Elixir ecosystem won't stop you from writing a network server that takes in a string and just blithely passes it along to a shell without analysis, overall the Erlang/Elixir ecosystem is very strong and lacks most of the footguns like an "eval" statement that get people. Though I will ding it a point for the most obvious way to run a shell command [1] taking just a string that goes to a shell rather than an array of parameters to a shell command.
It is on the higher end of secure languages to write a network server in.
> overall the Erlang/Elixir ecosystem is very strong and lacks most of the footguns like an "eval" statement that get people
Erlang has erl_eval [1] if you're looking for more ability to shoot yourself in the foot. You can call that from Elixir, but I guess that'd be weird; I'm not an Elixir person, but I'd bet you can shoot yourself in the foot if you try!
There's always fun with dist and proc_lib:spawn(Node, Fun) [2], which you can put in a list comprehension with erlang:nodes() [3] if you want to shot yourself in many feet rapidly ;)
[1] https://www.erlang.org/doc/apps/stdlib/erl_eval.html
[2] https://www.erlang.org/doc/apps/stdlib/proc_lib.html#spawn/2
[3] https://www.erlang.org/doc/apps/erts/erlang.html#nodes/0
All this foot shooting - this is the problem with permissive gun laws. We should ideally lock down all firearms to prevent any civilian doing harm. Only the select few government agents should own firearms.
obligatory /S (for internet)
also: 2 months ago I posted this Erlang SSH SFTP flaw - https://news.ycombinator.com/item?id=43126360
There absolutely is an eval function in the Elixir standard library:
https://hexdocs.pm/elixir/1.18.3/Code.html#eval_string/3
I’ve seen more horrendous code using macros in elixir even despite by brief foray than I have seen ever in decades of working in languages with eval. Like using them when normal functions would suffice.
Using macros when a function would do is a legit anti-pattern (and documented as such [1]) but unrelated to the security aspect as they are compile-time constructs.
The reason they were added to the language was precisely so meta and dynamic programming is done at compile time, which you can introspect before you deploy, versus doing it at runtime, which is how most dynamic languages tackle this. And those languages are most likely not using eval either, but intrinsic features that allow you to define classes, attributes, methods, and so on programmatically.
I’d say eval is discouraged in most languages, although it is useful for building things like REPLs and interactive environments.
[1]: https://hexdocs.pm/elixir/macro-anti-patterns.html#unnecessa...
> most obvious way to run a shell command [1]
I think you forgot a link to your [1] reference.
Just create your own.
That is quite the wrong way of looking at it. The vulnerability is in a implementation of SSH and not with the language/runtime itself; And it has already been patched. Erlang is a "managed" language and is quite secure compared to others.
You should definitely "sell" Elixir/Erlang/BEAM based languages to your management for a greenfield project; The opportunity is too good to pass up.
Nevertheless, if you would like to learn how to "harden" your Elixir/Erlang system, see the guidelines from the "Security Working Group" of EEF which i have linked to here - https://news.ycombinator.com/item?id=43717633
Honestly, no language is totally safe.
If I interpret the patch correctly the issue seems to be that you could just ask for a channel and do a request_exec before authenticating. The regression test is:
https://github.com/erlang/otp/commit/6eef04130afc8b0ccb63c9a...edit: Ah, found by the people at RUB, they do a lot of research in verifying protocol implementations iirc.
>RUB
For those not in-the-know, this is "Ruhr University Bochum".
https://www.ruhr-uni-bochum.de/en
They have quite a good reputation in the security research space.
I'm vaguely surprised that https://www.runzero.com/sshamble/ didn't find this. They did a scan over the entire internet trying invalid SSH state machine transitions, which I guess didn't cover this sequence.
I was too! The reason is that the Go x/crypto/ssh library was bailing out on the lack of reply to the channel open request, which prevented it from reaching the auth bypass check via exec. I should have an update out soon with this fixed and a RCE check for this issue.
The test server: $ erl -eval 'ssh:start(), ssh_dbg:on(), ssh:daemon(34222, [{system_dir, "/home/otp/ssh/keys"},{user_dir, "/home/otp/ssh/users/otptest/.ssh"}]).'
The exploit: auth.ScrapeExec(options, addr+" "+tname, res, ses, `os:cmd("touch /tmp/HAXXXED").`)
>-rw-r--r-- 1 root root 0 Apr 17 16:14 /tmp/HAXXXED
CWE-306, Missing Authentication for Critical Function, linked in the report seems to suggest the same. The score of 10.0 is damn spicy, too - you just ask the server to execute something for you, and it does so, no questions asked.
Design bug here: Clearly we need to run code as somebody, so, there's no reason to have infrastructure which just executes user code with the current context or server (presumably? or maybe an actual zero, ie root) context.
If we design the software this way, when we try to write the erroneous code we're caught - oh, wait, which user is authenticated? We need to... oh... we shouldn't be here without authenticating.
Afaik, if you were running the Erlang SSH daemon, when you connect as an authorized user (or just ask!), it drops you into the Erlang debug shell. There's no concept of different users in the debug shell. Erlang dist is kind of an almost single system image cluster, with no security boundaries once you're connected to the cluster. (Well, not exactly no boundaries, you can mark a process sensitive, and ets tables private, and do some other things to make introspection difficult [1], but you can likely still spawn an os process debugger and get to everything; you would need to modify the OTP sources to disable os process spawning)
I didn't think anybody would actually run the Erlang SSH daemon, but there's evidence that some do. It makes more sense to run openssh, so you can debug BEAM failures etc, and you can load a debug shell from your OS shell easily.
[1] https://security.erlef.org/secure_coding_and_deployment_hard...
> The issue is caused by a flaw in the SSH protocol message handling which allows an attacker to send connection protocol messages prior to authentication.
per https://www.openwall.com/lists/oss-security/2025/04/16/2
There’s something really strange and upsetting reading this on an archive site that wont be around for much longer..
It isn't going away!
For folks interested in the Security aspects of Erlang/BEAM languages the guidelines from Security Working Group of the Erlang Ecosystem Foundation are a good resource - https://security.erlef.org/ and https://erlef.org/wg/security
you could probably write a custom XDP program to parse and check for this payload using a tool like yeet and XDP_DROP it.
https://yeet.cx
you can try our sandbox at https://yeet.cx/play
[dead]