DEV Community

Tahir Almas
Tahir Almas

Posted on • Originally published at ictcrm.com

One Leaked Key: What the Beacon CRM Software Breach Teaches

Originally published at ictcrm.com

A UK CRM provider called Beacon confirmed this week that the breach affecting all of its 1,000-plus customers started with a single compromised AWS access key, likely exposed in publicly available JavaScript build artifacts. No zero-day, no phishing campaign, no insider. A credential that shipped to the browser along with the app.

Beacon serves charities and nonprofits, so the records involved cover donors, supporters, volunteers and fundraising history. That is exactly the kind of data that is worthless to a bank and very valuable to anyone running a targeted scam. If you are responsible for CRM software anywhere, this incident is worth twenty minutes of your attention, because the mistake behind it is common and the second mistake is more common still.

What actually happened

The earliest malicious activity Beacon can find is 27 July 2026, with data transfers happening across 27 and 28 July. The company disclosed in early August and published its root-cause finding in the week of 14 August.

The attacker used the key to reach an AWS environment holding customer database backups and downloaded them. The backups were encrypted at rest, which sounds like the story should end there. It does not. Beacon acknowledges the attacker may have been able to decrypt them before taking them, because whatever could read the backups could also reach what was needed to open them.

Exposed fields include names, phone numbers, email addresses and postal addresses. No bank details, sort codes or card numbers, because Beacon does not store them. The UK Charity Commission is monitoring the situation. No group has claimed the attack and the data has not surfaced publicly so far.

How a cloud key ends up on the public internet

Almost nobody commits a secret to a public Git repository any more. Scanners catch it, GitHub emails you about it, and most teams have a pre-commit hook. The exposure moved somewhere else.

The key never touches your repository. The build step publishes it for you.

The path runs like this. The key sits in an environment file, correctly excluded from version control, and everyone feels fine about it. Then a front-end build runs. Bundlers inline environment variables into the output so the browser can read them, because that is what they are for. The bundler also writes a source map next to the minified file, which conveniently reverses the minification for anyone who fetches it.

Now the key is a static asset on your CDN. Anyone can open developer tools, pull the bundle, and search it for the string AKIA. There are automated crawlers that do nothing else all day.

The reason this keeps happening is that the mistake is invisible from the inside. Your repository is clean. Your secret scanner passes. Your env file is git-ignored. Nobody on the team thinks to check the compiled output, because the compiled output feels like a build product rather than a published document. It is a published document.

The cheap version of not being here

Four things, none of which require a budget.

Scan your own deployed bundle. Fetch your production JavaScript the way an attacker would and grep it for credential patterns. Put it in CI so it runs on every deploy. This takes an afternoon to set up and would have caught this.

Stop shipping source maps to production. They are a debugging convenience for your team and a decompiler for everyone else. Upload them to your error tracker and keep them off the public host.

Give the front end a short-lived token, not a permanent credential. If the browser needs to talk to cloud storage, have your backend mint a scoped token that expires in minutes. A leaked token with a fifteen-minute life is an inconvenience. A leaked permanent key is this article.

Put an expiry on every key. Rotation is dull and it is the only control that limits the damage of a leak you never noticed. If a credential has no expiry date, its blast radius is the rest of your company's life.

The second failure was the logging

Here is the sentence from Beacon's statement that should worry you more than the key: specific objects, the exact destination of the downloads, and definitive attribution of which objects were accessed cannot be determined from available logs.

Read that again. They could see that data moved. They could not see which records. So when they worked out what to tell customers, they had to fall back on transfer volume, and their assessment from volume is that the actor exported everything in the database.

That may or may not be literally true. It does not matter, because when the logs cannot answer the question, you are obliged to assume the worst. Every customer gets the maximum version of the notification. The difference between "we can confirm 400 records were accessed" and "we must assume all of it" is not a technical difference. It is the difference between a contained incident and a company-defining one.

Four questions arrive within hours of any breach. Decide now whether your logs can answer them.

The questions that arrive on day one are always the same four.

Whose records were taken? Answering this needs object-level access logging. In AWS terms that is S3 data events, which are separate from management events and are off by default because they cost money. The bill for turning them on is trivial next to the cost of not being able to answer.

When did it start? Beacon's earliest evidence is 27 July. If your log retention is shorter than an attacker's dwell time, your earliest evidence is simply the day your retention window opens, which tells you nothing. Ninety days is a floor, not a target.

Was this credential ever used normally? A key used from a new country at three in the morning is the entire story, but only if you know what normal looked like for that key. That requires one credential per job. A single shared key used by six services has no baseline, because everything is normal for it.

Did they read the data or just copy it? Encryption at rest only helps if the decryption rights live on a different identity from the storage rights. If the same key opens the door and unlocks the box, encryption is documentation rather than defence.

Why this is an argument for self-hosted CRM software

Beacon's customers did nothing wrong. They picked a specialist provider serving their sector, which is normally the sensible choice. They had no way to audit whether a cloud key was sitting in a JavaScript bundle, no visibility into log retention, and no say in whether object-level logging was enabled. They found out about all of it from an email.

That is the trade in hosted CRM software. You hand over the operational burden and you also hand over the ability to verify anything. It works right up until it does not, and the failure is shared across every customer at once.

With a self-hosted deployment the calculation changes. You own the credentials, so you can rotate them. You own the logs, so you decide the retention. You can look at your own build output. Your breach, if you have one, is yours alone rather than an event affecting a thousand organisations simultaneously. We have written more on that trade in our piece on self-hosted CRM in 2026.

This is not a claim that self-hosting is automatically safer. A neglected self-hosted server is worse than a well-run managed one. The point is narrower: self-hosting converts an invisible risk into a visible one. You can fix problems you can see.

ICTCRM is open source and self-hosted for that reason. You read the code, you place it on infrastructure you control, and you configure logging to whatever standard your regulator or your board expects rather than whatever your vendor decided was cost-effective. For anyone holding donor, patient or client records, that control tends to matter more than the convenience it costs. It matters most in regulated sectors, which is part of why healthcare is the fastest-growing self-hosted CRM vertical.

What to do this week

If you run any CRM software, hosted or otherwise, three checks are worth doing before the weekend.

Pull your own production JavaScript bundle and search it for credential patterns. Check whether your source maps are publicly fetchable. Then look at whether your object-level access logs are on and how long they are kept.

If you use a hosted provider and cannot check those things yourself, ask them. The answers you get, and how quickly you get them, will tell you a lot. The strength of a vendor's security is usually visible in how comfortable they are being asked about it. We covered the related pattern of attackers simply logging in with valid credentials in an earlier piece on CRM credential abuse.

Frequently asked questions

What caused the Beacon CRM breach?

A compromised AWS access key, which Beacon says was likely exposed in publicly available JavaScript build artifacts. The attacker used it to reach an environment holding customer database backups and downloaded them. The earliest malicious activity found was 27 July 2026.

Was the stolen data encrypted?

The database backups were encrypted, but Beacon accepts that the attacker may have decrypted them before taking them. Encryption at rest only helps when the ability to decrypt sits on a separate identity from the ability to read storage.

How does an AWS key end up in public JavaScript?

Front-end bundlers inline environment variables into the compiled output so the browser can read them, and they often write a source map alongside it. If a cloud credential is in that environment file, it becomes a static asset anyone can fetch. The repository stays clean the whole time, which is why the mistake is easy to miss.

Why does the logging gap matter so much?

Because when logs cannot show which specific records were accessed, the organisation has to assume everything was taken. Beacon's own assessment, based on transfer volume, is that all data in the database was exported. Better logging often turns a total-loss notification into a much narrower one.

Does self-hosted CRM software prevent this kind of breach?

It does not prevent mistakes, but it puts them within your reach. You control credential rotation, log retention and build pipeline, and you can inspect all three. With a hosted provider you have no way to verify any of it until you receive a notification email.

What should I check first?

Fetch your deployed JavaScript bundle and search it for credential patterns, confirm your source maps are not publicly reachable, and verify that object-level access logging is enabled with retention longer than a realistic attacker dwell time. Those three take under a day and cover the failures in this incident.

Related resources

Details of the Beacon incident are drawn from the company's own disclosure and root-cause update, reported by SecurityWeek on 14 August 2026.

Top comments (0)