A Sleepless Night and a Curiosity
Today, I had a training session at work which required me to leave fairly early in the morning. As part of this work related training, we were required to complete some online computer modules which we were given links to ahead of time. With hopes of being allowed to leave early, I decided to stay awake and complete the online modules beforehand. One of these was the Ontario Ministry of Labour’s 4-step safety awareness module, which issues a certificate upon completion and is absolutely mandatory via company policy to work each year.
While working through it, a particular statement caught my attention: “Your results are not stored.” This immediately signaled that there was no backend database tracking progress—meaning everything had to be generated dynamically when the course was completed.
No Storage? Then How Is the Certificate Generated?
If no database is storing completion records, then the certificate must be created on-the-fly using data the browser provides. A quick analysis after finishing the course confirmed this. The certificate is generated through a request to a PHP file:
1 |
|
Notice the id
parameter—it’s a long string of seemingly random characters. But to anyone familiar with encoding techniques, the telltale =
at the end hints at something common: Base64 encoding.
Decoding the id
Parameter
Sure enough, decoding this Base64 string reveals the following JSON:
1 |
|
This JSON contains all the details used to generate the certificate—name, course title, language, and email. Something to note: some characters are URL-encoded, such as the period (.
) in the email being represented as %2E
. This is just properly handling special characters in the context of web browser URLs, and both %2E and ‘.’ are one in the same - only a ‘.’ when used in a web browser might be falsely interpreted as something else (like the ‘.’ between a subdomain.domain.TLD)
What Does This Mean?
This means the PHP file responsible for generating the certificate is relying entirely on client-side input. In other words, we can generate certificates with any name, any course title, and any email address, as long as we format the JSON correctly, encode it in Base64, and pass it as a parameter in a request.
Since we know the server doesn’t store or authenticate any of the data (as indicated at the beginning of the module), we can assume by sending it specially crafted information it will have nothing to reference and compare this data to.
Constructing a Custom Certificate
Using this knowledge, we can manipulate the data and generate a certificate with custom details. Here’s a simple way to do it:
- Create a JSON object with desired values:
1 |
|
- Encode it in Base64:
1 |
|
- Use the encoded string as the value for parameter ‘id’ in a POST request to the php endpoint determined to generate the certificate:
1 |
|
Or just send it via your browser..

Why This Matters
This isn’t just about exploiting a poorly designed certificate system—it’s about understanding how input validation, authentication, and server-side security should be implemented. A government-issued certification process that doesn’t validate completion on the server side opens up the potential for fraud. If certificates can be generated with any name, there’s no way for an employer to verify authenticity.
But lets be clear - by generating a certificate and avoiding the course, one is doing an injustice to themselves. Falsifying it, while absolutely in no way (in this case) could be proved, this particular course is designed to let you know what your rights are as a worked. It simply served as an example of how input validation is critical and can be abused.
Lessons Learned
- Always validate data on the server, not just in the client’s browser.
- Never trust user input blindly—especially when issuing official documents.
- Implement some form of authentication or tracking mechanism to ensure certificates are only generated for users who have legitimately completed the course.
Until then, the system remains a playground for anyone with a basic understanding of encoding and API requests.
Disclaimer: This article is purely for educational purposes. Manipulating government systems without authorization is illegal. This discusses manipulation of a public services output by sending it manipulated input, where no data is being stored to a database, no dangerous queries are causing damage or displaying sensitive data.