How Security Scanner Changed My Approach to Secure Coding


It started like any normal day.
The application was stable. Features delivered on time. QA was out. From the outside, everything looked perfect.
Then came the security scan report.
Findings pages.
High intensity. Moderate difficulty. Low difficulty.
Nothing was broken. No warnings were fired. No users reported problems.
However the report told a different story – not about what failed, but about what can fail.
At that moment I realized something important:
Security is not about what breaks today.
It’s about what attackers can use tomorrow.


Where the “Activation Code” is Not a Secure Code
Like many developers, I once believed that if an app worked and passed tests, it wasn’t enough.
A security analysis challenged that assumption.
It did not follow the path of happiness.
Look out for abuse, harassment, and serious crimes:
- What happens if the input is malicious?
- What if the token leaks?
- What if the dependency is compromised?
Suddenly, “working” was no longer the same as “safe.”
1. The First Wake Up Call: Cross-Site Scripting (XSS)
One of the first problems was a DOM-based XSS vulnerability.
I remembered the code clearly. It simply provides user input to the UI. The idea was pure. The feature worked as expected.
But the scan showed another side:
- Income created
- Text inserted into the DOM
- Running code in another user’s browser
What looked innocuous turned out to be an entry point for session theft and data exposure.


What I have learned
- User input is not always reliable – even if it looks harmless.
- dangerouslySetInnerHTML should only be used with clean content
- If HTML rendering is required, use a regular purification library like DOMPurify
What Has Changed
- Rendering of raw HTML has been avoided or obfuscated
- Output is escaped by default
- Input validation was present on both front and back
Bottom Line:
React automatically protects you from normal text rendering. Use DOMPurify if you need to render HTML or as an extra layer of security when sending data to your backend. Remember: authentication checks the format, cleanliness removes threats.
2. Injection Attacks: A Real-time Background Check
Next was the injection risk.
The frontend had guarantees. The input was blocked. Errors have been handled.
But the attacker never uses the UI.
Scanning focuses on the background – where user input meets the database.
Vulnerable Code (Python):
# User submits username and password
username = request.form.get(“username”)
password = request.form.get(“password”)
# Creating an SQL query with string formatting – DANGER!
query = f”SELECT * FROM users WHERE username = “{username}’ AND password=”{password}'”
cursor.execute(query)
What Could Go Wrong:
The attacker logs in as the username:
‘admin’ OR ‘1’=’1
The question that arises is:
SELECT * FROM users WHERE username=’admin’ OR ‘1’=’1′ AND password=’any’
Since ‘1’=’1′ is always true, the attacker bypasses authentication completely and gains access to the administrator’s account.
Secure Repair:
# Using parameterized queries – SAFE!
username = request.form.get(“username”)
password = request.form.get(“password”)
# Wildcards (%s) separate codes from data
query = “SELECT * FROM users WHERE username=%s AND password=%s”
cursor.execute(query, (username, password))
Why This Works:
Parameterized queries treat user input as data, not executable code. Even if an attacker tries to control’ OR ‘1’=’1, the database searches for a user literally named “admin’ OR ‘1’=’1” instead of making a false sense.
Example with FastAPI:


That was the shift:
Frontend authentication improves the experience.
Background authentication protects systems.
Repair
- Parameterized queries have been replaced by dynamic ones
- ORMs are used correctly instead of being overridden
- Access to the database was limited to what was strictly necessary
Injection attacks stopped being a theoretical threat and became real threats.
3. The Danger I Didn’t Write: Dependence
Some vulnerabilities were not in my code at all.
They lived inside third-party libraries – deep in the dependency tree.
Packages are out of date. Unsaved modules. Known security issues.
This was a very difficult lesson:
Modern applications inherit vulnerability in their dependencies.
New Habits
- Standard dependence test
- Removes unused packages
- Treat updates as a security feature, not an optional fix
4. Defense vulnerabilities: Invisible weaknesses
Remove flags from production.
Over-permissive CORS rules.
Verbose error messages.
None of this caused immediate failure.
They all expand the area of attack.
The configuration was something I reviewed with the same seriousness as the code.
What Security Scanning Really Teaches
At first, the scan felt like criticism.
In time, it felt like a direction.
Every input field.
Every API endpoint.
It all depends.
All configurations.
Each can reduce risk – or silently introduce it.
It did not suspect.
It revealed ideas.
It highlighted blind spots.
Security scanning forces developers to think like attackers.
That security scanner changed the way I code.
Not because it got problems –
but because it changed the way I think.



