Hacker Newsnew | past | comments | ask | show | jobs | submit | Sjoerd's commentslogin

What is the attack scenario here? Where are the security boundaries? How does the attacker gets their repository with a symlink in it to the victim? Is Helm typically run as a privileged user? How would this work? And why doesn't the vulnerability description give answers to these questions?


> What is the attack scenario here?

Given the details in the article, I think even something as simple a templating a chart from a repository might be vuln., but it likely depends on a lot of exact specifics.

> Where are the security boundaries?

I expect templating does not result in LCE.

> How does the attacker gets their repository with a symlink in it to the victim?

The attacker owns the repository. They can serve whatever maliciousness in it they want. But should templating a malicious chart result in LCE?

> Is Helm typically run as a privileged user?

Enough so, yes, because the rendered result is often pushed to a k8s cluster. "Privileged" here might not be "root", but it might be "this user has k8s API access".

Imagine, e.g., that the attacker's LCE here might be "push ~/.kube to attacker".

> And why doesn't the vulnerability description give answers to these questions?

Familiarity with the tools involved is an normal assumption.


Questions like this make me wonder if "hacker" news needs a rebranding.

Basic tech news?

Capitalist news?

Vulture Capitalist news?


To compensate for the US emissions of CO2 equivalent, you would need to create in the order of 4 cubic kilometers of charcoal every year. You could cover the whole of California with a layer of 1 centimeter (about half an inch) of charcoal every year.

So turning trees into charcoal scales up to a certain point, but not to the point that it "would even remotely make a difference for climate change", as OP said.


Yeah that sound about right given that we’ve burned enough coal already to lower whole regions by dozens of meters.


Do you have a link to that Yahoo publication? Or any more information on it?


probably not


I came to the same conclusion. Many string comparison implementations don't actually compare one character at a time. In one case strcmp seemed to compare eight characters at a time, so you would need to guess eight characters correctly to get a time difference. Glibc memcmp can compare 32 bytes at a time. In C# the timing of string compare depends on whether it does Unicode normalization or not. Even then, the difference is less than a nanosecond per compared character. It is not as straightforward that every string comparison between sensitive data and user input is at risk of timing attacks.

https://www.sjoerdlangkemper.nl/2024/05/29/string-comparison...


I love this, thanks for sharing. When I failed to get a measurable time difference myself I was worried I might just be doing something wrong and it'd get flagged the moment I published my research, so it's great to get confirmation from other people.


This differs for different template engines.

In Angular, for example, the template is parsed into a DOM tree, and then template variables are placed in the correct place. This makes injection really hard. In the above example, it would be impossible to break out of the div.

Other template engines just do a string search/replace, and this makes injection easy. Then it's indeed possible to break out of the div just by injecting </div>.

The example you quoted comes directly from the HTMX docs. They don't specify which template system is used, and I don't immediately recognize the syntax to limit it to a specific template system.


When doing symmetric encryption you usually need a nonce or IV, which is also sent to the other party along with the ciphertext and authentication tag. Why does the API for libsodium allow you to specify your own nonce and keeps it separate from the ciphertext? The function crypto_secretbox_easy includes the authentication tag in the ciphertext, but you still have to provide the nonce yourself and it is not included in the ciphertext. Wouldn't it be easier still if the nonce was generated within this function and also added to the ciphertext?


Many protocols define how the nonce must be computed.

And the nonce is not sent explicitly; the different parties compute it themselves the same way they agree on a shared secret.

When a ciphertext is received, the recipient knows what the nonce is expected to be, instead of having to trust an arbitrary one.

In the context of a stream of messages, it binds the nonce to a position in the stream, allowing detection of frames that have been replayed, reordered or lost.

But when the intent is to send independent messages, the nonce should be included with the ciphertext.

For constructions with a short nonce size, the ability to choose the nonce is also very useful to improve the security bounds, by using a key derivation function to derive a new key and nonce from a larger nonce.

By the way, for streams, libsodium has the `crypto_stream_*()` functions that greatly simplifies the implementation of protocols and file encryption.


In addition to what sibling comments said, keeping stuff separate helps making the C API a bit more explicit and easier to intuit out of the box. For instance: https://monocypher.org/manual/aead

  void
  crypto_aead_lock(
      uint8_t       *cipher_text,
      uint8_t        mac  [16],
      const uint8_t  key  [32],
      const uint8_t  nonce[24],
      const uint8_t *ad,         size_t ad_size,
      const uint8_t *plain_text, size_t text_size);
Here you see that both `nonce` and `mac` are separate (libsodium calls that "detached"), which can be annoying considering you always need the mac. On the other hand, the plaintext and ciphertext buffers have the same size, and the sizes of the mac and nonce are explicit.

Yet another reason to let users specify the nonce is that portability stops me from accessing an RNG. Can’t produce random nonces without it, so I have to pass the burden to the user. (On the other hand, I get to run on tiny microcontrollers that don’t even have `malloc()`).

---

Speaking of streaming encryption, I have that too now, and unlike libsodium it’s compatible with the one-shot interface. Like libsodium, you only need to provide your nonce once.


The docs have a page on encrypting multiple messages[0]. In it they use a single random IV and then increment it for each message. Under this scheme you only need to transmit or negotiate the IV once.

If you use something like TLS, The key exchange is expanded to produce an IV. Then each record has an incremented number[1] and this number is mixed with the IV to form a unique IV[2] for the message.

[0]: https://doc.libsodium.org/secret-key_cryptography/encrypted-... [1]: https://www.rfc-editor.org/rfc/rfc8446#section-5.3 [2]: https://www.rfc-editor.org/rfc/rfc8446#appendix-E.2


I agree. If you look at the Swift version of the library, it will generate and prepend the nonce for you automatically (if you use the right overloaded method). It will also strip it and use it during decryption.

My guess is they wanted to maintain compatibility with NaCl.


That would probably be good for the overwhelming majority of users.

More rarely, you want to save space/reduce overhead by using a deterministic IV scheme. Either all 0 because you picked a random key and you _really_ care about space saving, or you're very very sure you can safely count IVs (0, 1, 2, ..) without ever reusing a single one.

In those rare cases you don't want to transmit the IV, you just know what the value is supposed to be on both sides. More complexity and danger, but a small percentage of users get to save a few bytes.


A important benefit is that it keeps the function hermetic. Reproducibility is very important for fuzzing and debugging purposes. If the function lets me provide the nonce, I can use my own CSPRNG to generate it, and ensure that my program executes deterministically if fed the same random seed.


Nonce could be an implicit counter in which case it's not transmitted.


They aren't guessable, except for ULIDs generated by the same process in the same millisecond. To keep chronological order even within the same timestamp, ULIDs within generated within the same millsecond become incremental. This can become relevant for example when an attacker requests a password reset for himself and the victim simultaneously.


Interesting, I learned about ULIDs for the first time from this article, which says: "The remaining 80 bits [in a ULID] are available for randomness", which I read as saying those last 80 (non-timestamp) bytes were random, not incremental. But this was misleading/I got the wrong idea?

Going to the spec [1]... Yeah, that's weird. The spec calls those 80 bytes "randomness", and apparently you are meant to generate a random number for the first use within a particular ms... but on second and subsequent uses you need to increment that random number instead of generating another random number?

Very odd. I don't entirely understand the design constraints that led to a non-random "randomness" section still called "randomn" in the spec even though they are not.

[1]: https://github.com/ulid/spec


From what I gather this is done to persist the sort order. All calls within the same millisecond will get the same timestamp component so that can't be used to sort the ULIDs. So the "random" part is incremented and the resulting ULIDs can still be sorted by the order of function calls. This wouldn't be possible if the random part were truly random. I'm not sure this is a good idea but that is what I understood from the spec.


It’s not clear why they don’t just use a finer-grained timestamp component (e.g. nanoseconds) and increase that number if two events are within the same clock interval, and keep the random component random.


The reference implementation is written in Javascript and I don't think that provides a reliable way to get timestamps this fine grained.


The underlying clock doesn’t need to be fine-grained; only the target representation needs to be fine-grained enough for the additional increments inserted by the code that generates the IDs. Effectively, the precision of the timestamp part needs to be large enough to support the number of IDs per second you want to be able to generate sustainably.


Also, the spec notes there is an entropy trade off in using more bits for the time stamp. More timestamp bits is fewer random bits, because ULIDs constrained themselves to a combined total 128 bits (to match GUID/UUID width).


I agree that landscaping choices could be more environmentally friendly. However, planting trees in yards will have a limited impact; if 1.2 trillion trees cancel a decade of CO2 emissions, half a billion trees will cancel about 36 hours of CO2 emissions.


Very true. However, it would be better than all the demented proposals floating about.

The truth is that, short of a ground-braking discovery of a kind that is hard to describe we are not going to "save the plante" for thousands of years. No matter what we do.

We need to stop talking about destroying entire economies, solar panels, killing cars, trains and planes, and the ridiculous idea of buying carbon credits (really?) and start talking about the reality of this problem.

It is a planetary scale problem with a natural rate of change in the order of 100 ppm per 50,000 years. Anyone talking about "saving the planet" for the next generation or anything even remotely close needs to explain how we are going to accelerate this rate of change a thousand-fold without killing everyone in the process and using-up more energy than this planet can produce.

Basic scientific principle: You don't get something for nothing. If you are going to produce a planetary-scale change at 1000x the natural rate the side effects could be worse than the problem.

As I said before multiple times, the natural rate of change is what happened when humanity basically wasn't here --certainly our cities, power plants, planes, etc. were not here. Simple conclusion: If we destroy and eliminate ALL of humanity and all things we built it would take about 50,000 years to reduce atmospheric CO2 by 100 ppm. Anyone claiming to make a 1000x improvement to this rate of change while we are all still here (and our toys) has a supernatural problem to answer for.

Yes, sure, let's stop polluting unnecessarily. Swapping lawns and mowers for trees seems like a win-win at many levels. You stop producing pointless pollution, reduce water waste and convert carbon into trees. After that we need to look at reforestation at a massive scale.

I guess my point is that trees is the only "technology" we know we can deploy at scale without killing everyone on this planet in the process and using-up so much energy and resources that we'll create a larger problem.


Such a thing is typically called a deterministic password manager. One problem with it is that you can't change the algorithm. If you want to change your PBKDF2 from 1000 to 5000 iterations, then you can't login anymore on any of the services where you used this tool to set the password.

See also this https://news.ycombinator.com/item?id=13016132


You seem to seed the SecureRandom object with the current time. I think this reduces security and it would be better to omit the seed and let SecureRandom seed itself.

It also looks like you do normal String equals to compare secrets, which could be vulnerable to a timing attack.

Are you sure you are qualified to implement crypto?


Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: