JS

Application Security Series

5 CHAPTERS80% DONE
Week 4~ 12 min read

Small Security Issues That Shouldn’t Be Ignored: EXIF Exposure and Rate-Limit Weaknesses

When we talk about web application security, the conversation usually revolves around vulnerabilities such as SQL Injection, Cross-Site Scripting, SSRF, IDOR, authentication bypass, or Remote Code Execution.

But application security is not only about finding critical vulnerabilities.

During security testing, we often come across smaller issues that may not immediately result in account takeover or remote code execution, but can still expose sensitive information or make other attacks easier.

Two good examples are EXIF data exposure and rate-limit weaknesses.

EXIF exposure can unintentionally reveal information embedded inside uploaded images, while missing or weak rate limits can allow attackers to automate sensitive functionality such as login attempts, username discovery, password-reset requests, and OTP verification.

Individually, these issues may sometimes have limited impact. However, when combined with other weaknesses, they can become much more interesting from an attacker's perspective.

EXIF Data Exposure

EXIF stands for Exchangeable Image File Format.

When we take a picture using a smartphone or digital camera, the image can contain much more information than what we see visually.

For example, an image may contain metadata such as:

  • Camera manufacturer
  • Camera model
  • Date and time
  • GPS coordinates
  • Image dimensions
  • Software used to modify the image
  • Orientation
  • Author or copyright information

For example, an image uploaded to a website may visually look like this:

text
profile.jpg

But internally, it could contain metadata such as:

text
Camera Make       : Apple
Camera Model      : iPhone
Date Created      : 2026:09:29 18:21:13
GPS Latitude      : XX.XXXX
GPS Longitude     : XX.XXXX
Software          : iOS

The user may never realize that this information is being uploaded along with the photograph.

Why can this become a security issue?

The problem occurs when an application accepts an image from a user and publishes the original file without removing unnecessary metadata.

Imagine a real-estate website where a user uploads a photograph of a property.

The application stores the original image and makes it publicly accessible:

text
https://example.com/uploads/property/photo.jpg

If the original EXIF metadata is still present, someone who downloads the image may be able to extract GPS coordinates.

A security tester can inspect the image using tools such as:

bash
exiftool photo.jpg

If GPS information is present, the image may reveal the location where it was captured.

This becomes particularly interesting when the uploaded content is associated with sensitive locations such as homes, offices, restricted facilities, or private events.

EXIF Exposure Is Not Always a Vulnerability

It is important to understand the context.

The mere presence of EXIF metadata does not automatically mean that an application has a serious security vulnerability.

For example, a photography website may intentionally preserve camera information because it is part of the product's functionality.

The security concern becomes stronger when:

  • Sensitive metadata is exposed unnecessarily.
  • GPS coordinates are publicly accessible.
  • The original image is accessible to unauthorized users.
  • Users are not reasonably expecting the metadata to be published.
  • The application handles sensitive photographs.
  • The metadata exposes information that can create privacy or security risks.

Therefore, the impact depends heavily on what metadata is exposed and who can access it.

Testing for EXIF Exposure

During an authorized security assessment, a simple test can be performed.

Upload a test image containing known metadata and then download the image from the application.

Inspect it with:

bash
exiftool downloaded-image.jpg

Look for information such as:

text
GPS
Camera
Device
Date
Author
Software
Copyright

Then determine whether the application has:

  • Removed the metadata
  • Reprocessed the image
  • Created a new sanitized copy
  • Continued serving the original file

An important distinction is whether the application is serving the original uploaded file or a newly processed image.

A properly implemented image-processing pipeline can remove unnecessary metadata before the image becomes publicly accessible.

Rate-Limit Issues

The second category is rate-limit weaknesses.

Rate limiting is a security control that restricts how frequently a user, device, IP address, account, or other identifier can perform an operation within a specific period.

For example:

text
Password reset requests:
5 requests / 15 minutes

The exact values will depend on the application's requirements.

Rate limiting is particularly important for security-sensitive endpoints.

Common examples include:

text
/login
/forgot-password
/reset-password
/send-otp
/verify-otp
/register
/email-verification

Without appropriate rate limiting, an attacker may be able to repeatedly interact with these endpoints using automation.

Username Enumeration

One common rate-limit-related issue is username enumeration.

Username enumeration occurs when an application allows someone to determine whether a particular username or email address exists.

Consider a login endpoint.

An attacker submits:

http
POST /login

username=admin@example.com
password=wrongpassword

The application responds:

text
Invalid password.

The attacker then tries:

http
POST /login

username=random@example.com
password=wrongpassword

And receives:

text
User does not exist.

The difference between these responses tells the attacker that admin@example.com is a valid account.

The application has effectively created an account-discovery mechanism.

Username Enumeration Through Response Differences

The problem isn't limited to error messages.

Enumeration can happen through differences in:

  • HTTP status codes
  • Response body
  • Response length
  • Response timing
  • Redirect behavior
  • Headers
  • Error codes
  • JSON response fields

For example:

json
{
  "error": "USER_NOT_FOUND"
}

versus:

json
{
  "error": "INVALID_PASSWORD"
}

Even though the application may not explicitly say "this username exists," the difference allows an attacker to determine it.

Username Enumeration Through Forgot Password

Password-reset functionality is another common place where enumeration appears.

Consider:

http
POST /forgot-password

email=victim@example.com

The application responds:

text
Password reset email has been sent.

Now the attacker submits:

http
POST /forgot-password

email=random@example.com

And receives:

text
No account exists with this email address.

The attacker can now distinguish valid accounts from invalid accounts.

A better approach is to provide a generic response:

text
If an account exists for this email address, further instructions will be sent.

The same response can be returned regardless of whether the account exists.

This prevents the endpoint from becoming an easy account-enumeration oracle.

Missing Rate Limit on Forgot Password

Another common finding is a password-reset endpoint with no effective rate limiting.

For example:

http
POST /forgot-password

email=victim@example.com

If an attacker can repeatedly send this request without meaningful restrictions, the endpoint can be abused.

The consequences may include:

  • Password-reset email flooding
  • SMS flooding
  • OTP generation abuse
  • Increased infrastructure costs
  • Abuse of third-party email/SMS providers
  • User harassment
  • Increased noise around legitimate password-reset messages

Imagine an endpoint that sends an email every time the request is submitted.

An automated client could repeatedly trigger:

text
Request
   ↓
Password-reset email
   ↓
Request
   ↓
Password-reset email
   ↓
Request
   ↓
Password-reset email

This doesn't necessarily mean that the attacker can reset the victim's password.

However, the missing abuse control is still a security weakness.

Rate Limiting on OTP Generation

OTP functionality is another area where rate limiting is important.

For example:

http
POST /send-otp

phone=XXXXXXXXXX

If the endpoint generates and sends an OTP every time it is called, an attacker may repeatedly trigger OTP messages.

This can result in:

  • SMS flooding
  • Email flooding
  • Financial costs for SMS providers
  • User annoyance
  • Abuse of verification infrastructure

The application should therefore control how frequently OTPs can be generated.

For example:

text
OTP requested
     ↓
Start cooldown
     ↓
Additional requests temporarily restricted
     ↓
OTP expires

The exact timeout and limits should be based on the application's legitimate use case.

Missing Rate Limit on OTP Verification

OTP verification has a different problem.

Suppose an application uses a six-digit OTP.

There are:

text
1,000,000

possible six-digit combinations.

If an application allows unlimited verification attempts, automated guessing becomes possible.

For example:

http
POST /verify-otp

otp=123456

followed by:

http
POST /verify-otp

otp=123457

and so on.

A secure implementation should limit failed attempts and expire the OTP.

Additional controls can include:

  • Maximum verification attempts
  • Short OTP lifetime
  • OTP invalidation after successful use
  • Temporary throttling
  • Monitoring suspicious activity
  • Binding the OTP to the relevant transaction or session

Login Rate Limiting

Login endpoints are probably the most obvious place where rate limiting is expected.

Without appropriate protections, attackers can automate large numbers of authentication attempts.

A simplified attack could look like:

text
Username
   +
Password list
   ↓
Automated login requests
   ↓
Repeated authentication attempts

Rate limiting can make automated attacks substantially more difficult.

However, simply implementing an IP-based limit is not always enough.

For example:

text
100 requests / IP

can potentially be bypassed by distributing requests across multiple IP addresses.

Applications may therefore need a combination of controls involving factors such as:

text
IP address
Account
Session
Device
Endpoint
Application-wide traffic

The appropriate design depends on the application's architecture and threat model.

Be Careful With Account Lockouts

There is also a balance to maintain.

Suppose an application locks an account after five failed login attempts.

An attacker who knows a victim's username could intentionally submit five incorrect passwords.

The victim's account becomes locked.

The security control has now become an availability problem.

For this reason, applications should carefully design authentication throttling rather than relying exclusively on permanent or easily triggered account lockouts.

Progressive delays, throttling, monitoring, and other controls can sometimes provide better protection while reducing the possibility of attackers intentionally locking legitimate users out.

Rate Limiting Is More Than Returning HTTP 429

A common misconception is:

SECURITY_ADVISORY

"We return HTTP 429, therefore rate limiting is implemented."

Not necessarily.

A proper assessment should look at the actual behavior of the application.

For example:

text
Request 1 → Success
Request 2 → Success
Request 3 → Success
...
Request 20 → 429

This suggests some form of rate limiting.

But additional questions should be asked.

Is the limit based only on IP?

Can it be bypassed by changing accounts?

Can it be bypassed by changing sessions?

Does the sensitive operation still happen before the 429 response?

Does the application continue sending emails or SMS messages?

Does the restriction apply consistently across different application nodes?

Does the restriction reset too easily?

The goal is to determine whether the control actually protects the underlying functionality.

How These Small Issues Can Become More Interesting

One of the most important lessons in application security is that vulnerabilities don't always exist in isolation.

Consider this scenario:

text
Username Enumeration
        ↓
Identify Valid Accounts
        ↓
Weak Login Rate Limiting
        ↓
Automated Authentication Attempts
        ↓
Potential Account Compromise

Another example:

text
Username Enumeration
        ↓
Identify Valid Email
        ↓
Password Reset Endpoint
        ↓
Missing Rate Limiting
        ↓
Password-reset / OTP Abuse

And another:

text
EXIF Metadata Exposure
        ↓
Sensitive Information Disclosure
        ↓
Additional Information About Target

None of these chains automatically means that an account will be compromised.

The important point is that small weaknesses can provide useful capabilities that complement other vulnerabilities.

This is why security testing should not focus exclusively on individual vulnerability categories.

How Developers Can Prevent These Issues

For image uploads, applications should consider stripping unnecessary metadata before storing or publishing images.

A typical workflow could look like:

text
User Upload
     ↓
File Validation
     ↓
Image Processing
     ↓
Remove Unnecessary Metadata
     ↓
Re-encode Image
     ↓
Store Sanitized Image
     ↓
Serve Image

For authentication and recovery functionality, applications should implement appropriate abuse controls around:

text
Login
Password Reset
OTP Generation
OTP Verification
Email Verification
Registration
Username Recovery

Applications should also avoid revealing whether an account exists through different messages, response codes, or observable behavior.

Security Testing Checklist

When testing an application, some simple questions can reveal these weaknesses quickly.

Image Uploads

  • Does the application preserve the original image?
  • Is EXIF metadata removed?
  • Is GPS information exposed?
  • Can unauthorized users access uploaded images?
  • Is sensitive metadata publicly accessible?

Login

  • Is there effective authentication throttling?
  • Can valid usernames be identified?
  • Are error responses consistent?
  • Is throttling based only on IP?

Forgot Password

  • Can usernames or email addresses be enumerated?
  • Is there a generic response?
  • Can the endpoint be called repeatedly?
  • Are emails or SMS messages generated for every request?
  • Are reset tokens properly protected?

OTP

  • Can unlimited OTPs be generated?
  • Can unlimited verification attempts be made?
  • Does the OTP expire?
  • Is it invalidated after successful use?
  • Is there appropriate throttling?

Final Thoughts

Security isn't always about discovering a spectacular vulnerability.

Sometimes it is about noticing a small detail that developers overlooked.

An image that quietly exposes GPS coordinates.

A login endpoint that responds differently for valid and invalid usernames.

A password-reset endpoint that can be triggered thousands of times.

An OTP endpoint that accepts unlimited guesses.

Each issue may appear small when viewed independently.

But application security is about understanding how those small weaknesses affect the overall security of the system.

The best security assessments therefore don't stop at:

SECURITY_ADVISORY

"Is this exploitable?"

They also ask:

SECURITY_ADVISORY

"What information does this expose?"

SECURITY_ADVISORY

"What security control is missing?"

SECURITY_ADVISORY

"Can this functionality be abused automatically?"

SECURITY_ADVISORY

"Can this weakness be combined with another issue?"

That mindset is often what separates a simple vulnerability scan from meaningful security testing.

Janmejaya Swain's Blog — Security Research & Logs