I suspect the encryption here is broken due to CTR mode AES with IV reuse. Try printing out the IV in the segment function. It's the same value across sessions.
Another thing I see is that AES-CTR is being used alone, so there is no integrity guarantee for the messages.
I didn't have time to look into it any more deeply. The user interface and concept look really nice, but I would strongly recommend a cryptographic audit. In general, you shouldn't have to reach for the subtle constructs in a cryptographic library to build product features.
> I suspect the encryption here is broken due to CTR mode AES with IV reuse. Try printing out the IV in the segment function. It's the same value across sessions.
I think it's a little more subtle. IVs are being generated deterministically, but keys are generated randomly per session. The nonce uniqueness requirement in CTR is per key. That said, there doesn't seem like there's any guard against replays of messages, or dropping of messages, or altering of messages.
> Another thing I see is that AES-CTR is being used alone, so there is no integrity guarantee for the messages.
Indeed. They seem to try and do some integrity checking at the start of a session by sending an encrypted all-zero block, as a way of verifying that the client has the correct key (stored in the url hash). From what I can tell, there's no integrity checking on any subsequent messages.
Also the KDF parameters for Argon2id seem way underpowered (19MB RAM, 1 lane, should probably be using at least 2GB RAM in a KDF setting)
Thanks for the comment, happy to elaborate. You're correct that the IVs are not reused.
Replays and dropping messages are not possible due to the indexing of the stream. This is a necessary precaution from a distributed systems sense because networks can fail or deliver messages twice.
Integrity / detecting server tampering of data is not really part of the security model here — I've discussed this in my comment below, but the aim of the encryption is to make sure to preserve confidentiality.
---
Argon2id parameters are set as strong as possible while allowing for execution in a browser context.
> Thanks for the comment, happy to elaborate. You're correct that the IVs are not reused.
Perhaps you can elaborate a little more on this? For subsequent calls to the segment() function, holding the stream ID constant, how are IVs generated?
> Replays and dropping messages are not possible due to the indexing of the stream. This is a necessary precaution from a distributed systems sense because networks can fail or deliver messages twice.
I see. I was mainly looking at the encryption side of things, not the application layer.
> Integrity / detecting server tampering of data is not really part of the security model here
This seems like an own-goal, especially since you could've gotten it pretty much for free using an AEAD construction like GCM(I understand you're using the seeking capability of CTR, but it isn't clear to me why).
> Argon2id parameters are set as strong as possible while allowing for execution in a browser context.
This is incorrect. They're actually set to as weak as possible while still being safe for use in a password hashing context. I hunted around a while for the parameter set you've opted for here, and finally found it[0]. Is this where you got it from? Importantly, that parameter set is optimized for a minimum security margin in the context of hashing passwords. None of the KDF parameter sets in the Argon2 RFC[1] approach that level of RAM usage. I just ran Argon2id with 5 passes 500 MB RAM in my browser and it executed in a couple seconds.
It's also unclear why you need a KDF at all. From what I can tell, users can't specify the password that gets KDF'd into your AES key. Why are you trying to key stretch a 14 character alphanumeric password? Why aren't you just reading 16 random bytes and storing that in the URL hash?
Hey, this is a serious accusation. I would be very careful about raising false suspicions like this publicly. The application does not reuse IVs.
For your second point, I am aware of authenticated encryption and the possibility of bit-level tampering with commands. The point of the encryption is to make sure to preserve confidentiality here.
Tampering with commands is not really part of the threat model. The server needs to be trusted in some regard. If the server were compromised and actually modified commands, and it could send arbitrary network messages, then it could just change the HTML payload to the website and show the end user something different.
The point of the encryption is only to preserve confidentiality with a properly running server, so CTR mode was chosen.
I appreciate your dedication to security, but I would strongly advise you do more research before making comments like this — I take security very seriously as well, and making vague, unfounded accusations without actually reading the code only serves to confuse people.
Hey, this is a serious accusation. I would be very careful about raising false suspicions like this publicly.
It's not an 'accusation', it's feedback on your thing. It could be mistaken but it's a Show HN, the purpose is public feedback. If that sort of feedback is not what you're looking for, don't do a Show HN.
Once again, security is very tricky to get right, and I'm very transparent about the security model and encryption of the application. I've discussed this at length and have thoroughly documented the code.
The commenter makes factual errors, and stating something is insecure, even on the level of suspicion, is a claim that as software developers, we take very seriously.
It doesn't matter if the commenter is wrong or right, you can't start writing grumpcomments with threatening auras at them. Particularly as an author in a Show HN but really anywhere on HN in general. If you think the critique is wrong, you can address that without hyperbole and without suggesting they're making accusations or need to 'be careful'. People are allowed to be simply wrong and if you think they are, you can explain that to them.
The comment says that the IV is reused. The IV is not reused! I am very open to feedback, but false statements about the security of an application need to be taken very seriously, especially when given from a commenter who speaks with a tone of authority on the subject.
If I am truly unwelcome to do a Show HN, please let me know — but I think I have comported myself reasonably. I'm just trying to share something of interest to people!
I intended this to be constructive feedback and I'm sorry if it came off as otherwise. Even if the IVs themselves aren't actually problematic, I think the main point is that users of this would be interested in integrity being part of the threat model. To me, there is a tangible difference between trusting the server with complete shell access and only trusting it to deliver frontend assets that I can inspect. Additionally, using misuse-resistant cryptography constructs and libraries is a good practice to avoid some of these problems entirely. I look forward to seeing iterations, since otherwise this is very nice work.
The other comments make it fairly clear that this suspicion was unfounded but convinced people otherwise, and I have given a fair response to your comments. I of course appreciate you scrutinizing the application, and while the feedback was constructive, comments about the brokenness of a security model need to be taken very seriously.
---
From the application perspective, the root of our disagreement seems to be that you would prefer using higher-level managed cryptographic primitives. I understand this criticism, but there were systems reasons why these were not appropriate for sshx. I agree with you that for most standard applications, you would avoid having to use stream ciphers directly as much as possible. sshx kind of straddles the boundary of what's technically feasible with real-time stream multiplexing and communication though.
I'm glad you find the work interesting, it's something I've spent a lot of time on!
You're exactly right. The IVs are completely predictable, and crucially, that allows us to guarantee that they are not reused. The security of CTR mode of encryption depends on avoiding IV reuse.
Once again, I'm very happy to have this discussion at length! I just would prefer a context where people are not confused by misleading information from the start, and the readers are able to spend time thinking about it.
My concern with the comment is that it speaks from a position of authority and raises a lot of false alarms about the security of the application.
The anonymous commenter publicly shared a suspicion of something that is 1) very serious and 2) false, and it essentially forces me to respond immediately. That is really stressful, especially since it's a tricky technical subject that a general audience of software developers is not expected to be familiar with.
It's hard to explain why the comment is vague without giving more cryptographic background. I cannot disprove IV reuse in a short comment of this regard.
It's an imperfect analogy, but imagine writing a piece of systems software and someone commenting "this leaks memory, just add a print statement to line N. I don't have time to look more." I could show them in a couple minutes why they were incorrect about line N, but "leaks memory" in general is a very vague accusation that could refer to any part of the program, as are the comments about integrity and AE and so on.
To most casual readers, you're a pseudonymous and unknown poster too (and that goes for nearly everybody, really).
it essentially forces me to respond immediately. That is really stressful
There are a lot of processes and rules to make Show HN welcoming and unstressful - it has extra guidelines, accepts a very wide variety of work in terms of quality, size, polish, etc. But it can't remove the stress of public feedback, including potentially inaccurate public feedback and you can't start going after your critics like that because of it.
I have been experimenting with similar idea myself. I was curious on how you handle instantiating the terminal state for new clients. Seems like you're storing a buffer [0] of past output, and replaying that?
Super cool. Our students are using ttdy[0] and tmux for providing shared access to a configured environment, but your solution seems much more flexible :) I'm going to start experimenting with it for our next courses, thanks!
I’ve been using GoTTY (https://github.com/yudai/gotty) to do the same thing, combined with ngrok or Cloudflare tunnels to get a publically accessible URL. To enable multiplayer mode, just need screen/tmux.
Nice trick! Many people have mentioned that tmux lets you share terminals, though worth noting that it takes a bit of setup, doesn’t render correctly when you have different screen sizes, and requires stitching together a lot of other tools to work over a browser.
Personally I think being able to arrange and resize terminals adds a lot to the collaboration feeling, as well as seeing people’s cursors. I encourage you to give it a try! (it takes less than a second to install, and then you just run “sshx”)
Web developers live in the web, but we still need to interface with VMs over SSH. Bridging that gap in favor of the developer is genius. The multiplayer aspect, the shell one-liner to bootstrap the whole process, everything about this is great.
Thanks! Yeah you can use it anywhere with outbound HTTP network access, whether that’s a local VM, cloud instance, laptop, k8s pod, random managed SaaS, serverless function, Raspberry Pi, …
I'm not sure about this criticism — the script is written to be as simple as possible and also has a comment about this if you do inspect it as you suggest.
# This is a short script to install the latest version of the sshx binary.
#
# It's meant to be as simple as possible, so if you're not happy hardcoding a
# `curl | sh` pipe in your application, you can just download the binary
# directly with the appropriate URL for your architecture.
You're also welcome to install it any way you choose! The code is fully open-source, and it has straightforward instructions to build from source.
I don't think it's anything nefarious. Can't pipe a brotli'd response into bash. My browser wasn't accepting the 'identity' encoding. If you alter your browser to accept 'identity', it will return the script.
I'm not sure honestly, if you could raise an issue I'd appreciate it. I didn't go out of my way to do this; it seems to be some default of SvelteKit or the server code that I don't understand?
Seems like something to do with your deployment server config. You may be redirecting all pages to your fallback spa.html. I built the site and served it with `python3 -m http.server --dir build` and it served the script to the browser without an issue.
tmate is an incredible piece of software! The terminal multiplexing is surprisingly similar to the problem of collaboratively sharing terminals, and forking tmux is a really elegant way to handle that. I took a lot of inspiration from other terminal software out there
You need a key to access the terminal, and the key is never sent to the server or over the network, it goes in the browser hash. You could say the same about Jupyter being a web access tool, for instance.
sshx only lets you make ephemeral connections and isn’t meant to be a remote access tool
All session IDs and encryption keys are cryptographically generated. And sshx refuses to connect except over TLS
If you give someone a link they can access your terminal right? Then none of the rest matters. A URL isn't a secret. Hence it's unathenticated remote access. Which is nuts.
Every competent network admin in every company should be blocking this right now. What a crazy risk to open up for the sake of laziness.
Another thing I see is that AES-CTR is being used alone, so there is no integrity guarantee for the messages.
I didn't have time to look into it any more deeply. The user interface and concept look really nice, but I would strongly recommend a cryptographic audit. In general, you shouldn't have to reach for the subtle constructs in a cryptographic library to build product features.