Hacker News new | past | comments | ask | show | jobs | submit login
League of Legends database compromised, passwords hashed without salt (leagueoflegends.com)
93 points by Strom on June 9, 2012 | hide | past | web | favorite | 104 comments

Is it just me or have the number of announcements on HN about password leaks gone up in the last few weeks?

I think availability bias is kicking in, with each additional announcement, more links about announcements are posted (for karma) or more sites feel like they can announce, under the cover of larger leaks, that they themselves have been compromised.

Probably just me.

[1] - http://en.wikipedia.org/wiki/Availability_heuristic

It seems to me that there have been a few more lately than usual. I'm all for it though; the only way sites are going to start treating passwords responsibly is if they're embarrassed into doing it.

I'm OK with that. Hash leaks are big news.

I haven't seen what was the weakness exploited in all these attacks -- perhaps it's a common vulnerability that was discovered by a group of bad guys.

Not just the last few weeks, the last few days. I was already drawing that conclusion before this disclosure, and internally speculating that the same group or person might be responsible.

I'm nearly positive the US code salted the hashes (it's been a long time since I was in that code :). I say US code because (again, memory is dim) I think they had a partnership with a company in the EU and that (might have) included authentication.

The platform guys at Riot were the sharpest group of engineers I've worked with. Smart and able to get stuff done without bike shedding. They did stuff right.

It is possible to tell the passwords were unsalted because: "We compared encrypted password hashes and discovered that 11 passwords were shared by over 10,000 players each" and one of the points of salting is to make impossible to identify identical passwords from the hashes.

Not really. You get that with per-password salting, but having a single salt for your whole database is not uncommon. Since the main point of salting AFAIK is to ward off rainbow tables, it's better than nothing.

EDIT: As noted in the comments, the way I put this originally was kind of flip and misleading and I apologize for creating confusion. My point was that I've seen a number of places do it that way, so just throwing at at your problems doesn't necessarily fix everything.

A single salt for the whole DB is not salting. It is no different than a (custom) hash function, which does not prevent identifying identical passwords, and which does not prevent rainbow table cracking.

Preventing rainbow table attacks is exactly what a custom hash function would do. You can't precompute hashes if you don't know the hash function. But you're right that a single salt in conjunction with a known hash function generally provides little additional protection, although this depends on the size of the salt.

A few years back I started a project to create rainbow tables for Oracle hashes with friends. The old Oracle hashing algorithm was pretty weak, but used the username as a salt. Within a few weeks we had rainbow tables for lots of default oracle accounts.

Moral of the story is to use a unique salt per account, but don't roll your own crypto in the process.

A good cryptographer assumes that a custom hash function does not prevent rainbow table attacks, because he should not assume the algorithm will remain secret (security by obscurity, yadi, yada).

The right way to prevent a rainbow table attack is to computationally prevent it via unique salts.

Unique salts are absolutely the correct way to rainbow-proof a database of hashes[1]. But a novel hash function will still do the trick and isn't comparable to using a single salt across the entire database, as you originally claimed.

Reverse engineering a novel hash function, while theoretically possible, isn't a capability possessed by the folks dumping passwords from LinkedIn or Riot. And even if it were, doing so would cost more than would be gained by compromising those passwords[2].

Thus, in practical terms, a novel hash function is a great way to undermine attackers, not unlike using Linux or opening files in non-standard viewers (LibreOffice, Nitro PDF Reader, etc.).

1. And if you have access to a good cryptographer, you should absolutely roll a novel hash function as well. Security through obscurity is the proverbial cherry on top of your defensive sundae, i.e. it's only a bad thing if you rely on it exclusively.

2. Not to mention that the whole point of rainbow tables is that they've already been computed. If an attacker has to reverse engineer a hash function to create a rainbow table, that largely defeats the rainbow table's purpose.

1. No. A good cryptographer will tell you to not re-invent crypto and to use existing peer-reviewed hash functions. This is why the NIST is hosting an open competition for selecting the future SHA-3.

2. This is exactly what happened with the custom proprietary "obscure" GSM A5/1 encryption algorithm. First it was reverse engineered (based on a leak), then David Hulton and Steve Muller created rainbow tables for it. The fact that it was a custom algo did not defeat the rainbow table's purpose.

There are many ways a custom hash algo designed by a company could end up being used across multiple of its password databases, and could subsequently be leaked, making the generation of rainbow tables possible and valuable (by rogue employees or hackers), that relying on the obscurity of a custom algo is a bad idea. As you recognized, salting is the ultimate protection. So there is no point in talking about alternatives.

But a novel hash function will still do the trick and isn't comparable to using a single salt across the entire database, as you originally claimed.

I'm not sure I understand this point, what is the criteria for a function to be novel?

This function produces different hashes from most other hash functions, eg, it is new and possibly novel, but is equivalent to using a single salt across a database:

    function novelHash(password) {
        return md5("novelHash" + password);

Yes but it's not like the random hacker has a 600 gig rainbow table for MD5('DATSALT' + PW). If you REALLY want to do the right thing when it comes to storing passwords, you need to use a hash algo that is computationally hard enough to brute force, it should take at least .5 sec on a good computer to compute. Every couple years, you should add another pass of the algorithm, ie. F(F(X)), to compensate for faster computers. By adding the extra pass, you won't need the original password to generate the new, revised, stronger custom hash algo. If you do this, in 10 years your passwords will still be secured. Also, salt your passwords with each a unique at least 100 random bytes, shouldn't need to be said.

Not an expert, but I believe rehashing the hashes is a good way to decrease entropy.

As long as the salt is added for each recursive iteration, it should destroy any kind of cryptographic hints given by hashing a hash. So you shouldn't be doing F(F(F(X))) rather it should be F(SALT + F(SALT + F(SALT+X)))

But anyhow, I was talking about increasing the security of an already-existing hash algorithm. Even if the recursive hashing isn't that much more secure, it definitely isn't less secure than one pass...

normally salt is some random string unique for each user, but you have to store the salt of each user in database for authentication, if your database is hacked and they got both your hash and salt, it is really no difference between salt and no-salt


So if I have access to that salt, I generate a new rainbow table and get a huge percent of your users.

The point of salting is to make rainbow tables no more efficient than brute forcing. If each user has a unique salt, there's literally no benefit to generating a rainbow table.

Then the rainbow table can only be used with this specific site. This makes it no more efficient than brute forcing. You can store the hashes yes, but you can also include the cracked passwords in the dictionary and it takes only slightly more time to compute them even with unique salts.

Site-wide salting has almost the same security as per-user salt, as long as the salt is not leaked or cracked before the database is leaked for pre-computation.

A database-wide salt makes cracking the database as hard as forcing one password. You only need to do the computation once and then you have a super-quick lookup for all the other hashes. Per-entry salts totally bust that.

>This makes it no more efficient than brute forcing.

Jesus, no. It absolutely does make it more efficient than brute forcing each password.

I compute one rainbow table that I can run against 10,000 users. Or I brute force 10,000 users' passwords because they have unique salts.

>_< God, I need to just accept the fact that people are going to talk out their ass about this and stop trying to get people to spread bad, insecure information.

oh sweet jesus of irony, you're the guy that was wrapped up in Bitcoinica.

Oh, I got it. My brain wasn't working then.

Don't worry, I use per-user salts for all my web projects following all security best practices that I know.

Out of curousity - is it a salt if you do something like this:

salty = md5(md5(pw) . pw . 'poniesaremagical' . md5(username));?

It is per-user... how is it different than using a timestamp which will be as unique as username?

Technically yes, but don't use md5 for anything security-related ever. It's broken. http://www.mscs.dal.ca/~selinger/md5collision/ is just one example. (I also remember reading some years ago that md5s within md5s can make the resulting hash more vulnerable to certain attacks but I don't have any formal knowledge in cryptology to say for sure.) Use bcrypt/scrypt and you're automatically protected from both rainbow tables and brute force.

H(Salt . H(Password)) is a lot like an hmac (minus the secret part and the padding). I'm not sure about the pre-image vulnerability mentioned on wikipedia's md5 page, but as for collision vulnerabilities, according to wikipedia's hmac page, "HMACs are substantially less affected by collisions than their underlying hashing algorithms alone. Therefore, HMAC-MD5 does not suffer from the same weaknesses that have been found in MD5."

It's not salty enough for my taste. What you've done is no different than:

  H(H(Password) + Salt)
If I steal your db and have another db that contains your user's unsalted password hashed with the same hash function, I can easily test if the same password is used in both places, simply by replacing H(Password) with the other hash. This leaks information and provides incentive to continue trying to crack the easiest target, if I really want what you have.

A simple change makes this comparison impossible:

  salty = H(H(Password + Salt)
Now there's no place to plug in the other hash, so I can't tell if the accounts share passwords until I successfully crack one and try it on the other. I might not bother and focus on lower hanging fruit.

Always assume your salting method is public, even if you make attempts to keep it secret. And remember that your site isn't in isolation; your user and every site they interact with are also potentially weak links in the chain.

Note that the examples above are oversimplified. You should look to a better authority on how to properly store passwords. In a future leak, we'll be surprised that the sites involved only salted their passwords.

Yes, as long as you use some salt data that is unique per user (timestamp, random number/guid/whatever) (you have to store that obviously), then it's fine. The problem is acting as if a site-wide salt is an ok-thing. It's not.

Incidentally, as the guy who started this whole thing, I'd just like to note that I actuslly agree with this. When I said they were "OK" or whatever, I meant it in the sense of "I guess it's good they're doing something," not like I'd recommend it. Please nobody get that idea.

Parent is talking about the League of Legends North American region which does not necessarily share its authentication code base with the European regions which were the ones compromised.

Ok. That would make sense. The parent seemed to claim the leaked passwords were salted.

You left out an 'un' in front of salted. Or you're wrong. I'm hoping you just mistyped. [edit :)]

Oops. Fixed. Thanks.

I forgot what bike shed was. It is focusing on trivial things


Really? They always seemed quite incompetent to me. Upgrades frequently took 3 to 4 times as long as planned. Unscheduled downtimes happened at least once a week. Matchmaking took forever even when servers were busy, and when asked about it on the forums, the developers described their matchmaking algorithm as one that ran in n!! time on the numbers of players looking for a game.

Why would the US and EU installations have different code or database schemas?

Due to the strange syndication/franchise model that Riot has used in the past when setting up in regions other than North America.

If I remember correctly the franchisee gets source access and can write their own game lobby code if they like.

Exactly this. They did the same thing with Ten Cent in China, I believe.

which is a terrible decision for users that registered before EU exists, just in case you have similar buisness plans.

We can't actually tell much about their password storage mechanism from that post. For one, they mention "encrypted hashes", which might mean encryption, might mean hashes, or might mean both; for two, they don't describe how they determined which users had weak passwords. If they were using some kind of reversible encryption scheme, it's possible that they ran that function against their database and determined common passwords that way.

I'll give them the benefit of the doubt, unlikely as it may be, because if they were in fact doing something as stupid as SHA1 or MD5 or ROT13, and they still opened their post with "Keeping player information secure is very important to Riot", then somebody needs to be strangled as an example to other mealy-mouths.

I also take issue with telling your users what kind of passwords to use. If you're storing passwords correctly, and if you're blocking brute force attempts, it almost doesn't matter what password your users are using. (Almost: somebody could still try "password" on an account and get lucky if it's one of the 10,000 accounts with that password.)

"We compared encrypted password hashes and discovered that 11 passwords were shared by over 10,000 players each."

You can't do that with salt. That's half the point of salting.

Of course you can. It's just more computationally expensive.

I realize that it's super unlikely that that's what they did, but that doesn't change the fact that at the moment all we know about their password storage system comes from a badly worded PR piece.

No. God, I hope we don't find out they're use symmetric encryption. Do I need to explain why that's a stupid idea?

In case I do: 1) The site doesn't need my password in plaintext. 2) If the server is compromised, the attackers don't just have salted or unsalted hashes THEY HAVE FULL PLAINTEXT PASSWORDS (unless it's some weird case where they have DB but not FS access).

No, either way, they're wrong.

(Sigh, I'm sorry for the snippiness, I'm just tired of coming into everyone of these threads with people who earnestly try to regurgitate what they heard from the last thread about this and manage to give bad advice or implications.)

No, you didn't need to explain that. (I hear ya though.)

Yes, they are probably wrong. However, unlike the recent LinkedIn leak, at the moment we know almost nothing about how they were storing passwords. (Although, according to a thread on their forums, they did leave a user's previous and current passwords both simultaneously active -- not a good sign.)

I think that HN didn't used to so readily confuse speculation and facts.

A lot of game companies don't get valid email addresses from most of their user baseso if they don't have a good email to authenticate a password reset, leaving the old password active sometimes is the only option to authenticate users for a password reset.

Well, considering they said they compared "hashes" later on, and the hopeful unlikeliness that they were really using symmetric encryption, I feel like it's a pretty sure educated guess and not just a knee-jerk reaction.

edit: I didn't mean to be personally chastizing in my first post, I'm just extremely distraught at the advice I see in these threads, the continued confusion of people and the fact that people with massive userbases either aren't paying attention or are in this ignorant group of "it won't happen to me" people.

It says encrypted not hashed, these are not the same thing. Encryption uses keys and without the keys you can't get the value without a huge brute force effort. Hash without salt can be broken trivially. It'd bad either way but encrypted is way better than leaked hash.

I believe they mean hashed (as pointed out later in the article) but if it was encryption I'd disagree pretty strongly with the assertion it's safer than straight hashing.

If you don't need the original password, hashing should be used, not encryption. Hashing means there is no issue of key management as is the case with the encryption system. If those keys are mishandled then it's trivial to recover all the plaintext passwords.

Decryption would be difficult without the keys, but it's likely that (a) they have keys stored somewhere insecure or (b) they'd perform the encryption with a single key for all passwords. For (b), this means you simply had to have a valid account and you'd have a plaintext-ciphertext pair to bruteforce. Once that single key is extracted you'd have access to all the other passwords as well.

Come on now, this is a PR release. Most users aren't going to know what "hashed" means, but most people do know what encrypted means. There's nothing to be deduced from their using the word encrypted.

Later it says "We compared encrypted password hashes" so they are probably hashed.

That is an admission, otherwise this act would be futile.

"We think someone stole animals from our pet shop, so we compared the empty cages to filled ones to figure out..."

I was going to ask: is there actually any benefit salting a password that will be encrypted?

It is really kind-of very good practice to salt passwords. We've talked a bit about this recently here on HN:



Despite the other reply you got (which was my original 'lol'), no, there isn't an advantage to salting a password that is going to be encrypted with symmetrical encryption. I mean, what would that even mean?

Encrypt("salt"+"password", key) = ENCRYPTED_DATA

Decrypt(ENCRYPTED_DATA, key) = "salt"+"password"

In short, it is BEST to HASH with a salt. Hash with a salt and don't use symmetrical key encryption methods.

Yup, always hash with a salt (or use an algorithm that does it for you). I added another example below for this guy. And yes, definitely don't use symmetric encryption.

Thanks. I'm no security expert but I couldn't see how it would make a difference.

Sure, to help illustrate it further: (don't use SHA1, I'm using it to avoid a discussion of why you wouldn't manually use a salt with bcrypt)

user1: SHA1("salt123"+"puppydog11") = SOME_HASH

user2: SHA1("salt456"+"puppydog11") = SOME_DIFF_HASH

This way, even for the same password, there are different salts, and thus different hashes. No one can run a rainbow attack unless they've generated rainbow tables for that salt (frankly, it would be possible, but useless to generate a rainbow table for a specific salt)

LinkedIn, LastFM, League of Legends... What is with this disturbing trend of websites beginning with L being cracked all in the same week?

Well obviously the bad guys are just going through the phone book one by one.

Well we haven't had a good Microsoft service hack for a while. Microsoft Xbox Live next?

Maybe a competence between groups, with one of the rules being "the domain must start with L" :) OR maybe just a coincidence...

To me, it adds insult to injury when companies that fail to take the most basic, well-known measures to protect their login databases always tell us how much they value the security of user information.

That would only be acceptable if the next words were, "and therefore we have fired the CTO and all programmers involved".

I don't understand why this keeps happening. When someone designs the user/password model for a website or software do they serious not even consider properly encrypting the passwords? This is not rocket science, implementing a relatively secure password hashing setup takes a minimal amount of work. Hell, adding a salt is an extra field in the database, an extra line of code when creating a user and an extra "+salt" when computing the hash.

I honestly think they spend more time coming up with ridiculous password requirements than actually encrypting the passwords. Possible dialog:

Dev 1: The passwords must have at least one symbol, one number, no dictionary words, and it can't be longer than 15 characters.

Dev 2: That'll be pretty secure, which hashing functions should we use? And should we salt it?

Dev 1: I think MD5 should be secure enough and salts are just overkill.

Your post would be more convincing if you didn't inaccurately refer to this as "encryption".

Technically hashing is one-way encryption, so while ambiguous it's not exactly completely wrong.

Looks like it's only the EU databases that were compromised, so if you have an NA account like I imagine most people here here would, no need to panic (though changing your password anyway won't hurt anybody).

That sounds like a really proffessional letter to their users. Brief, honest, precise, and they clearly state what their action items to prevent this from ever happening again will be. I like it a lot.

Is "info" acceptable in professional business communications now? I don't mind that it's friendly and informal, but I also wouldn't call it professional.

Is there a good authentication system that doesn't involve storing passwords, hashed passwords, or encrypted passwords in the master database?

Yes. A great, practical and scalable example is found in ssh: http://en.wikipedia.org/wiki/Secure_Shell#Key_management I'll try to explain how it works in non-technical terms (so please don't nitpick as I'm glossing over details)

User generates a public and private keypair. The public key is given to the remote site (such as LoL or Linkedin), but the public key is not secret -- it is public. You can post it on your blog, whatever. You can use it for multiple accounts without concern.

The public key allows one to encrypt some data, but the public key cannot decrypt the data.

The private key can decrypt the data.

When the user wishes to log in the remote site, using the public key, encrypts a random string and sends it to the user. If the user manages to successfully decrypt this random string and send it back then the remote site can infer that the user holds the private key -- because only the private key can perform the decryption.

The private key is never sent to a remote party. Only meaningless random strings are communicated over the wire.

The (significant) drawback to this method is that the user will have to have the private key with them in order to perform the authentication. But perhaps mobile devices will solve that problem for us.

I would love to see an ssh-like key exchange built into browsers. You add your key to the site, GitHub style, and then you use that for auth. No more nonsense with OAuth or "remember my password" or the remote site having your password just because they grabbed the DB. It's just a useless public key to them.

TLS Client Authentication[1]? I believe this is what StartSSL[2] is using for user to access their control panel.

The biggest problem is it is so user unfriendly.

[1]: http://www.browserauth.net/tls-client-authentication

[2]: http://www.startssl.com/

SSL Client certificate authentication has existed in browsers for a long time. Browsers even have built in key generation, but noone uses it. Probably because the UI is not very good.

Mozillas new BrowserID scheme is pretty similar to this too.

PKI as implemented by SSL Certs is needlessly complicated, which is a big part of why no one has adopted it for end user authentication. Compare what I described above to the mess described here: http://en.wikipedia.org/wiki/Public-key_infrastructure

A decentralized key system as ssh provides is much more appropriate for end users.

It's built in. Many companies use it internally.

In fact, I can't think of any VPN I've ever connected to that didn't require a machine certificate. Cisco VPNs I've used require it, as does my own personal VPN.

There's Secure Remote Password, which stores a non-reversible verifier instead: http://en.wikipedia.org/wiki/Secure_Remote_Password_protocol

Apparently it's quite tricky to implement properly though.

Cryptographic hashes are "non-reversible" too. But they're both vulnerable to offline dictionary attacks if the attacker obtains the host's secrets -- which I think is what `astroduck' was really asking about, leaked server databases like this news story.

(I don't see how there's any possible protocol that behaves otherwise: if Alice is capable of proving she possesses a secret to Bob through a protocol, then Bob can always discover Alice's secret by playing that protocol with himself, enumerating every possible secret until the protocol succeeds. And so can anyone who knows everything that Bob knows about Alice's secret.)

The SRP paper doesn't say much about this except that brute-force dictionary attacks are "expensive". I don't think they make specific claims about computational hardness like scrypt. The paper was written in 1997.

"An attacker who captures the host's password file cannot directly compromise user-to-host authentication and gain access to the host without an expensive dictionary search."


It's also quite tricky to explain to your investors and your customers that your password database was stolen.

Maybe some day there will be "Security as a Service" where someone helps you do this properly.

I believe @tptacek will gladly accept your money for this service. As will Cigital.

"Security as a Service" that does what? Teaches you how to store data securely, explain to investors that user data was stolen or an outsourced password verification utility.

The first can be done if people would bother to learn and completely understand what they're doing (this thread and the corrections I've had to make seems to prove that people think they know what they're doing when they don't).

The second, have fun with.

The third is already solved. oAuth, OpenID, Facebook Connect, Twitter, BrowserID, etc.

All these sites have to do is store the passwords using bcrypt and with salts and they're pretty much uncrackable (as far as we know).

The reason they're uncrackable is because when using bcrypt it takes a second or more to generate a hash for a password (compared to 0.000001 seconds for md5) meaning if they want to try and brute force the password or build a rainbow table it'll take them years instead of seconds to crack each password.

There's no need to remote password storage, they just need to learn more about password security.

Federated identity doesn't replace passwords, it just punts the whole process of authentication to a third party. That third party will still need to authenticate the user somehow, which brings us right back where we started.

But it allows the passwords to be stored by someone who specializes in security.

It'd be nice if everyone who runs a non-trivial website stayed was a security expert, but we're also busy with other aspects of the site.

No. Simple passwords properly stored and monitored provide the best balance between user experience and security.

Keep in mind that the target audience of this post is a largely nontechnical user base. These days, average people are getting a general idea of the meaning of "encrypt" due to the prevalence of, e.g. SSL in e-commerce, but not necessarily the meaning of "hash". Thus, it's not uncommon that places will intentionally misuse these words in order to reach a nontechnical audience.

Just be sure you don't use your LoL password on any other game/email. The hackers will very likely test the info against your email and diablo 3.

Your weakest link is the website with the weakest security. Now they will try your password on your other accounts.

Well, to be pedantic, there's no such thing as a "diablo 3" password, only a battle.net password. A WoW account is more lucrative.

If they got my account info... not a big deal. all my high priority pass' have unique passes managed by keepass.

Ante one knows how they got access to the database?

European servers only, according to their release.

every beginner scripting kiddie now knows to at least salt their hashes

who is working for riot then? seriously who?

Good god, this topic is discussed to death and yet there are spreading very inaccurate, insecure crap in this thread. I think everyone needs to stop giving advice and speculating about what is "good" and defer to a security expert or a set of codified best practices. I just don't understand how some people seem to understand salting, hashes or encryption but not enough to understand why unique-per-user salts are important, why asymmetric and symmetric encryption differ or why encryption has nothing to do with this style of password storage. If you don't understand these things, stop giving security advice in these threads.

>but not enough to understand why unique-per-user salts are important

I don't think that's been covered in this thread. If the main point of salting is to make rainbow tables ineffective, a single DB-wide hash still does that. Presumably if a hacker gets a copy of your entire database, they still don't have a copy of your hashing function with that salt. So then they're reduced to brute force.

Something else that I just thought of is, if you're salting per user, where does that salt get stored? A secondary database?

..And then come to find out it's been discussed down thread. Oops.

Any competent security architect will assume that if the bad guy gets a copy of the entire password database he also gets a copy of the entire codebase, all design documents, installation instructions, and operations manuals, and designs the system to be secure against that.

To whomever downvoted me, I've seen people suggest on this thread or ones in the last 24 hours that:

- symmetric encryption is appropriate for sites' storing passwords

- md5 is okay

- site-wide salts are just as secure as user specific salts

and more. Some of these were suggested by people that have far, far more karma than me. Some were suggested by people that had had this explained to them in previous threads and then took it upon themselves to mis-convey this information back. I don't have a pony in this race as I use different strong passwords per-site and I don't have user data to worry about. I just cringe everytime I see potential hackers reading this misinformation or hackers potentially with data who don't understand their risk or blindspots. I only mean the best, even if I come off exasperated.

Don't forget the guy that salted his own passwords - googlepassword, linkedinpassword, yahoopassword (yeah ... he probably has a Yahoo account).

How is this bad?

I mean sure, if you can get access to one password, you will be able to predict passwords for other websites, however, these SALT + WEBSITE-passwords tend to end up very, very long, which makes it very hard to break. Afterall, every single password you listed there is at least 13 characters long.

I sense a lot of misinformation in the comments, do you know of a site or book that covers the best practices that we should be using?

What's not compromised this week?

Anything special happening? Is it Friday 13 and stoner dot something again? Heck even the kitchen computer at my grandmas house may have been target this week... Hopefully that one had salt. Tum dum tiss.

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