Some of the biggest data breaches in history started with things that sound surprisingly simple: a secret left in code, a system that trusted a user too much, a software bug that exposed information, or sensitive information being written into logs.

Here are five real-world examples and what developers can learn from them.

1. Leaving Secret Keys in Code — The Uber Breach

One of the most famous examples involves Uber.

In 2016, attackers gained access to an Uber private GitHub repository. Inside the repository, they found credentials that could be used to access Uber’s Amazon Web Services environment.

Those credentials gave access to sensitive information belonging to Uber riders and drivers.

The U.S. Federal Trade Commission later said that Uber had allowed engineers to use an access key with broad administrative privileges over sensitive data. The attackers ultimately obtained information involving millions of people. (Federal Trade Commission)

The important lesson isn’t simply:

“Don’t put passwords on GitHub.”

It’s broader than that.

Developers sometimes put secrets directly into code because it’s convenient. The application needs a password or access key, so the developer puts it somewhere the application can read it.

The problem is that source code tends to travel.

It gets copied, backed up, shared with other developers, stored in repositories, and sometimes accidentally exposed.

And even if a repository is private, that doesn’t mean a secret inside it is automatically safe.

What developers can learn

Sensitive credentials should be kept outside the source code and managed using appropriate secret-management systems.

And there’s another important lesson from the Uber case:

A secret should not have more access than it needs.

If a key only needs to read one type of information, it shouldn’t automatically have permission to access everything.

2. Trusting the User Too Much — The TalkTalk Breach

In 2015, British telecommunications company TalkTalk suffered a major cyberattack.

The attackers exploited a weakness known as SQL injection in several of TalkTalk’s web pages.

You don’t need to understand SQL injection to understand the basic problem.

Imagine a restaurant where you are supposed to order from a menu.

The restaurant expects you to say:

“I’d like a chicken sandwich.”

But instead, someone finds a way to give the kitchen a completely different instruction:

“Ignore the menu and give me access to the entire kitchen.”

That’s roughly the idea behind SQL injection: unexpected input is interpreted as an instruction by the system.

In TalkTalk’s case, the attackers were able to use the vulnerable webpages to access an underlying database containing customer information.

The UK’s Information Commissioner’s Office found that the attack exposed personal information belonging to 156,959 customers. In 15,656 cases, bank account details and sort codes were also accessible. (ICO)

The investigation also found that the database software was outdated and that a security fix had been available for more than three years.

What developers can learn

Never assume that the information coming from a user is safe.

A user might be a normal customer entering their name.

But they could also be someone deliberately trying to make the application do something it wasn’t designed to do.

Every application should treat external input as potentially untrusted and handle it safely.

3. Checking Who Someone Is but Not What They’re Allowed to Do — Facebook’s 2018 Attack

In 2018, Facebook disclosed a serious security vulnerability involving its “View As” feature.

The feature was designed to let people see what their profile looked like to someone else.

Sounds harmless.

But a combination of three software bugs allowed attackers to steal special login credentials called access tokens.

Think of an access token as a temporary digital key.

Instead of entering your password every time you use Facebook, the application can use this digital key to recognize that you’ve already logged in.

Attackers were able to steal these keys and potentially take over accounts.

Facebook initially estimated that around 50 million accounts had been affected; its investigation later determined that attackers had actually stolen access tokens for about 30 million people. (About Facebook)

This is a good example of why authentication and authorization are so important.

The application needs to answer two different questions:

“Is this really you?”

and:

“What are you allowed to do?”

A weakness in the way Facebook handled these digital keys allowed attackers to effectively obtain the keys needed to act as other users.

What developers can learn

Never assume that because someone has successfully logged in, every action they attempt should automatically be allowed.

Every sensitive action should have appropriate checks around identity, permissions, and the credentials being used.

4. Putting Sensitive Information Into Logs — Twitter’s Password Problem

Logs are one of the most useful tools developers have.

When an application stops working at 2 a.m., developers often look at the logs to figure out what happened.

But logs can become dangerous when they contain information that should have remained private.

In 2018, Twitter announced that a bug had caused some users’ passwords to be written to an internal log before the passwords were properly protected.

Twitter said it had discovered the problem itself and had found no indication that the passwords had been misused or accessed by outsiders. Nevertheless, it recommended that users change their passwords. The company said the issue potentially affected all of its users at the time more than 330 million accounts. (Safeguard)

Think about what happened here.

The passwords weren’t intentionally published.

The problem was that a debugging or logging process accidentally recorded information that should never have been recorded.

It’s a bit like a bank keeping a detailed diary of every customer’s PIN number simply because the diary was useful for troubleshooting.

Even if nobody steals the diary, storing those PINs creates an unnecessary security risk.

What developers can learn

Logs should contain enough information to investigate problems, but not sensitive information that doesn’t need to be there.

Developers should be particularly careful with:

  • Passwords
  • Authentication tokens
  • API keys
  • Credit card information
  • Personal information
  • Private messages

A useful rule is:

If you wouldn’t want it printed on a piece of paper sitting on your desk, think twice before putting it in a log.

5. Thinking “It Works” Means “It’s Secure” — The TalkTalk SQL Injection Example

Here’s a mistake that is particularly easy for developers to make:

Testing whether something works isn’t the same as testing whether it’s secure.

Again, the 2015 TalkTalk breach provides a good example.

The affected webpages were functioning normally. Customers could use them.

But attackers weren’t using the webpages in the normal way.

They were deliberately trying to make the application behave differently from what the developers expected.

The UK’s Information Commissioner’s Office found that the attack used SQL injection vulnerabilities that had been well understood for many years and for which known defenses existed. It also found that TalkTalk had experienced earlier SQL injection attacks against the webpages before the major incident. (ICO)

This illustrates an important difference.

A normal test might ask:

“Can a customer use this page?”

A security test asks:

“What happens if someone tries to abuse this page?”

Those are very different questions.

A feature can work perfectly for a normal customer while still being dangerously vulnerable to someone intentionally trying to break it.

What developers can learn

Developers shouldn’t test only the normal path.

They should also think about abnormal behavior:

  • What if someone enters unexpected information?
  • What if someone changes an ID?
  • What if someone sends thousands of requests?
  • What if someone skips the website and talks directly to the underlying system?
  • What if someone tries to access another user’s information?
  • What if someone deliberately sends malformed data?

Security testing is essentially asking:

“What happens when someone doesn’t play by the rules?”