How a Security Scan Changed My Approach to write Secure Code

Sanjay Kumar G

2 min read

approach to secure code

It started like any normal day.

The application was stable. Features were delivered on time. QA had signed off. From the outside, everything looked complete.

Then the security scan report arrived.

Pages of findings.
High severity. Medium severity. Low severity.

Nothing was broken. No alerts were firing. No users had reported issues.
Yet the report told a different story — not about what had failed, but about what could fail.

That was the moment I realized something important:

Security is not about what breaks today.

It is about what attackers can exploit tomorrow.

When “Working Code” Is Not Secure Code

Like many developers, I once believed that if the application worked and passed tests, it was good enough.

Security analysis challenged that assumption.

It did not follow the happy path.
It looked for misuse, abuse, and edge cases:

  • What happens if input is malicious?
  • What if a token is leaked?
  • What if a 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 issues was a DOM-based XSS vulnerability.

I remembered the code clearly. It simply rendered user input into the UI. The logic was clean. The feature worked exactly as expected.

But the scan showed the other side:

  • A crafted payload
  • A script injected into the DOM
  • Code execution in another user’s browser

What looked harmless became an entry point for session theft and data exposure.

What I Learned

  • User input is never trustworthy — even when it looks harmless.
  • dangerouslySetInnerHTML should only be used with sanitized content
  • When HTML rendering is necessary, always use a sanitization library like DOMPurify

What Changed

  • Raw HTML rendering was avoided or Sanitized
  • Output was escaped by default
  • Input validation existed on both frontend and backend

The Bottom Line:

React protects you by default for normal text rendering. Use DOMPurify when you need to render HTML or as an extra security layer when sending data to your backend. Remember: validation checks format, sanitization removes threats.

2 . Injection Attacks: A Backend Reality Check

Next came injection vulnerabilities.

The frontend had validations. Inputs were constrained. Errors were handled.

But the attacker never uses the UI.

The scan focused on the backend — where user input meets the database.

The Vulnerable Code (Python):

# User submits username and password

username = request.form.get(“username”)

password = request.form.get(“password”)

# Building SQL query with string formatting – DANGEROUS!

query = f”SELECT * FROM users WHERE username='{username}’ AND password='{password}'”

cursor.execute(query)

What Could Go Wrong:

An attacker enters as username:

‘admin’ OR ‘1’=’1

The resulting query becomes:​

SELECT * FROM users WHERE username=’admin’ OR ‘1’=’1′ AND password=’anything’

Since ‘1’=’1′ is always true, the attacker bypasses authentication entirely and gains access to the admin account.​

The Secure Fix:

# Using parameterized queries – SAFE!

username = request.form.get(“username”)

password = request.form.get(“password”)

# Placeholders (%s) separate code 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 admin’ OR ‘1’=’1, the database searches for a user literally named “admin’ OR ‘1’=’1” instead of executing the malicious logic.

Example with FastAPI:

That was the shift:

Frontend validation improves experience.

Backend validation protects systems.

The Fix

  • Parameterized queries replaced dynamic ones
  • ORMs were used properly instead of bypassed
  • Database access was limited to what was strictly required

Injection attacks stopped being theoretical risks and became concrete threats.

3 . The Risk I Didn’t Write: Dependencies

Some vulnerabilities were not in my code at all.

They lived inside third-party libraries — deep in the dependency tree.

Outdated packages. Unmaintained modules. Known security issues.

This was the hardest lesson:
Modern applications inherit risk from their dependencies.

New Habits

  • Regular dependency audits
  • Removing unused packages
  • Treating updates as a security task, not optional maintenance

4 . Security Misconfiguration: The Invisible Weakness

Debug flags in production.
Overly permissive CORS rules.
Verbose error messages.

None of these caused immediate failures.
All of them widened the attack surface.

Configuration became something I reviewed with the same seriousness as code.

What Security Scanning Really Teaches

At first, the scan felt like criticism.

Over time, it felt more like guidance.

Every input field.
Every API endpoint.
Every dependency.
Every configuration.

Each one can either reduce risk — or silently introduce it.

It did not accuse.
It exposed assumptions.
It highlighted blind spots.

Security scanning forces developers to think like attackers.

That security scan changed how I write code.

Not because it found issues — 

but because it changed how I think.

Related posts:

Leave a Reply

Your email address will not be published. Required fields are marked *