<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Abhinav Singwal</title>
    <description>The latest articles on DEV Community by Abhinav Singwal (@abhinavsingwal).</description>
    <link>https://dev.to/abhinavsingwal</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2914312%2F452f11ca-f061-4f95-a0f2-c76390b4e5c9.jpg</url>
      <title>DEV Community: Abhinav Singwal</title>
      <link>https://dev.to/abhinavsingwal</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/abhinavsingwal"/>
    <language>en</language>
    <item>
      <title>When a Phone Number Field Accepts Negative Numbers: A Look at Input Validation Failures</title>
      <dc:creator>Abhinav Singwal</dc:creator>
      <pubDate>Sat, 13 Jun 2026 10:03:33 +0000</pubDate>
      <link>https://dev.to/abhinavsingwal/when-a-phone-number-field-accepts-negative-numbers-a-look-at-input-validation-failures-5931</link>
      <guid>https://dev.to/abhinavsingwal/when-a-phone-number-field-accepts-negative-numbers-a-look-at-input-validation-failures-5931</guid>
      <description>&lt;p&gt;During a recent web application assessment, I came across an interesting issue that demonstrates why input validation remains one of the most important aspects of application security.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ondc5t8q11kcmr76nv3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ondc5t8q11kcmr76nv3.png" alt="Contact Form Issue"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Observation
&lt;/h2&gt;

&lt;p&gt;A phone number field was expected to accept valid telephone numbers. However, while testing the application, I discovered that the field accepted negative numeric values such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-27
-90
-137
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These values were processed and accepted by the application without any apparent restrictions.&lt;/p&gt;

&lt;p&gt;At first glance, this may appear to be a minor issue. After all, accepting an invalid phone number does not immediately result in account takeover or remote code execution. However, findings like this often reveal deeper problems in the application's validation logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does This Matter?
&lt;/h2&gt;

&lt;p&gt;Applications rely on user-supplied data for business operations, reporting, notifications, integrations, and analytics. When invalid data is allowed into a system, it can create unexpected behavior throughout the application.&lt;/p&gt;

&lt;p&gt;Some potential impacts include:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Data Integrity Issues
&lt;/h3&gt;

&lt;p&gt;Phone number fields are designed to store contact information. Allowing invalid values can pollute databases and reduce the reliability of stored data.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Business Logic Problems
&lt;/h3&gt;

&lt;p&gt;Many workflows depend on valid phone numbers, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SMS verification&lt;/li&gt;
&lt;li&gt;Customer communication&lt;/li&gt;
&lt;li&gt;OTP delivery&lt;/li&gt;
&lt;li&gt;Account recovery processes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Improper validation can interfere with these workflows and lead to unexpected application behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Input Validation Gaps
&lt;/h3&gt;

&lt;p&gt;When one field lacks proper validation, it often indicates that similar weaknesses may exist elsewhere in the application.&lt;/p&gt;

&lt;p&gt;Security testers frequently use small validation failures as indicators that broader validation issues may be present.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Downstream Processing Risks
&lt;/h3&gt;

&lt;p&gt;Applications often share data with external systems such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CRM platforms&lt;/li&gt;
&lt;li&gt;Marketing tools&lt;/li&gt;
&lt;li&gt;Reporting systems&lt;/li&gt;
&lt;li&gt;Third-party APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unexpected values can cause failures, exceptions, or inaccurate reporting within these connected systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Client-Side Validation Is Not Enough
&lt;/h2&gt;

&lt;p&gt;Many applications rely heavily on frontend validation using JavaScript. While this improves user experience, it should never be considered a security control.&lt;/p&gt;

&lt;p&gt;Attackers can easily bypass client-side restrictions using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Browser developer tools&lt;/li&gt;
&lt;li&gt;Proxy tools&lt;/li&gt;
&lt;li&gt;Modified requests&lt;/li&gt;
&lt;li&gt;Automated scripts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All validation rules must be enforced on the server side before data is accepted and stored.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recommended Mitigations
&lt;/h2&gt;

&lt;p&gt;To prevent issues like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Validate all inputs on the server side.&lt;/li&gt;
&lt;li&gt;Enforce strict phone number formats.&lt;/li&gt;
&lt;li&gt;Reject unexpected characters and negative values.&lt;/li&gt;
&lt;li&gt;Implement length restrictions.&lt;/li&gt;
&lt;li&gt;Use allowlists instead of blocklists whenever possible.&lt;/li&gt;
&lt;li&gt;Perform consistent validation across all application interfaces and APIs.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>contactform</category>
      <category>form</category>
      <category>htmlform</category>
      <category>phoneinput</category>
    </item>
    <item>
      <title>Business Logic Vulnerability: When Multiple Accounts Can Share the Same Payout Details</title>
      <dc:creator>Abhinav Singwal</dc:creator>
      <pubDate>Mon, 08 Jun 2026 07:02:38 +0000</pubDate>
      <link>https://dev.to/abhinavsingwal/business-logic-vulnerability-when-multiple-accounts-can-share-the-same-payout-details-3384</link>
      <guid>https://dev.to/abhinavsingwal/business-logic-vulnerability-when-multiple-accounts-can-share-the-same-payout-details-3384</guid>
      <description>&lt;p&gt;Business logic vulnerabilities are often overlooked because they do not always involve classic security issues such as SQL Injection, Cross-Site Scripting, or Remote Code Execution. Instead, they arise when an application's workflow allows actions that conflict with the intended business rules.&lt;/p&gt;

&lt;p&gt;One interesting scenario involves payout settings.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Scenario
&lt;/h2&gt;

&lt;p&gt;Imagine a platform that allows users to receive payments through bank accounts, gift cards, cryptocurrency wallets, or other payout methods.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjidglji9brbpefkqbh9m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjidglji9brbpefkqbh9m.png" alt="Business Logic Issue in Payout System" width="296" height="567"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A user can navigate to their profile and configure payout information that will be used to receive future rewards or payments.&lt;/p&gt;

&lt;p&gt;Now consider the following workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User A registers an account.&lt;/li&gt;
&lt;li&gt;User A adds a bank account and payout email.&lt;/li&gt;
&lt;li&gt;The platform saves the information successfully.&lt;/li&gt;
&lt;li&gt;User B registers a completely different account.&lt;/li&gt;
&lt;li&gt;User B enters the exact same payout information.&lt;/li&gt;
&lt;li&gt;The platform accepts the details without any validation or review.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As a result, multiple accounts become associated with the same payout destination.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Is This Interesting?
&lt;/h2&gt;

&lt;p&gt;At first glance, this may appear harmless. However, from a business logic perspective, payout information is often treated as an identifier that links financial transactions to a specific user.&lt;/p&gt;

&lt;p&gt;Allowing the same payout destination to be associated with multiple accounts can create challenges for fraud detection, abuse prevention, and account attribution.&lt;/p&gt;

&lt;p&gt;The issue is not necessarily the duplicate data itself. The real concern is how that data may be used by other business processes within the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Potential Risks
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Multi-Account Abuse
&lt;/h3&gt;

&lt;p&gt;Many platforms attempt to limit abuse by restricting rewards, promotions, referrals, or bonuses to one user.&lt;/p&gt;

&lt;p&gt;If the same payout destination can be reused indefinitely, a single individual may create multiple accounts while still directing all payments to a single destination.&lt;/p&gt;

&lt;h3&gt;
  
  
  Referral Program Abuse
&lt;/h3&gt;

&lt;p&gt;Referral systems frequently assume that each participant represents a unique individual.&lt;/p&gt;

&lt;p&gt;When payout destinations are not validated, an attacker may create multiple accounts and funnel rewards to the same financial endpoint.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fraud Investigation Challenges
&lt;/h3&gt;

&lt;p&gt;Security and fraud teams often rely on payout information to identify relationships between accounts.&lt;/p&gt;

&lt;p&gt;If duplicate payout information is allowed without monitoring or review, suspicious activity may become harder to investigate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ban Evasion
&lt;/h3&gt;

&lt;p&gt;Platforms sometimes ban accounts involved in abuse or policy violations.&lt;/p&gt;

&lt;p&gt;If payout information is not used as part of anti-abuse controls, a banned user may create additional accounts while continuing to use the same payout destination.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Security Researchers Can Test This
&lt;/h2&gt;

&lt;p&gt;When assessing payout systems, researchers can examine the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can multiple accounts register the same bank account?&lt;/li&gt;
&lt;li&gt;Can multiple accounts use the same payout email address?&lt;/li&gt;
&lt;li&gt;Are duplicate cryptocurrency wallet addresses accepted?&lt;/li&gt;
&lt;li&gt;Is there any verification process for payout ownership?&lt;/li&gt;
&lt;li&gt;Does the application generate warnings when duplicates are detected?&lt;/li&gt;
&lt;li&gt;Are duplicate payout destinations reviewed by fraud systems?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The objective is not merely to identify duplicate data acceptance but to understand how the platform's business processes interact with that data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example Test Flow
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create Account A.&lt;/li&gt;
&lt;li&gt;Add a payout destination.&lt;/li&gt;
&lt;li&gt;Create Account B.&lt;/li&gt;
&lt;li&gt;Add the same payout destination.&lt;/li&gt;
&lt;li&gt;Observe whether the platform:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Rejects the entry.&lt;/li&gt;
&lt;li&gt;Generates a warning.&lt;/li&gt;
&lt;li&gt;Requires additional verification.&lt;/li&gt;
&lt;li&gt;Accepts the data silently.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Documenting these behaviors can help identify weaknesses in fraud prevention and account attribution mechanisms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security Recommendations
&lt;/h2&gt;

&lt;p&gt;Organizations can reduce risk by implementing several controls:&lt;/p&gt;

&lt;h3&gt;
  
  
  Server-Side Uniqueness Checks
&lt;/h3&gt;

&lt;p&gt;Validate whether a payout destination already exists before saving it to another account.&lt;/p&gt;

</description>
      <category>businesslogicvulnerability</category>
      <category>cybersecurity</category>
      <category>payoutbugs</category>
      <category>owasptop10</category>
    </item>
    <item>
      <title>How I Find Excessive Data Exposure in APIs</title>
      <dc:creator>Abhinav Singwal</dc:creator>
      <pubDate>Sat, 06 Jun 2026 09:22:57 +0000</pubDate>
      <link>https://dev.to/abhinavsingwal/how-i-find-excessive-data-exposure-in-apis-3nab</link>
      <guid>https://dev.to/abhinavsingwal/how-i-find-excessive-data-exposure-in-apis-3nab</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1jifoqbj9rf1t34fxxal.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1jifoqbj9rf1t34fxxal.png" alt="Excessive Data Exposure in APIs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was testing a fintech app's "View Profile" feature. The mobile app showed my name and avatar. Burp Suite showed something else entirely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"avatar"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/images/avatar.jpg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"john@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"phone"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"+1234567890"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"password_hash"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reset_token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"a7b3f9e2c4d1g6h8j9k0l"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"internal_risk_score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"admin_notes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Flagged for unusual activity"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"last_login_ip"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"192.168.1.100"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The app only showed &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;avatar&lt;/code&gt;. The API returned &lt;strong&gt;everything&lt;/strong&gt; about me - including my password hash and an active reset token.&lt;/p&gt;

&lt;p&gt;That was my first &lt;strong&gt;Excessive Data Exposure&lt;/strong&gt; bounty. $1,500 for reading my own data.&lt;/p&gt;

&lt;p&gt;Let me show you how to find these everywhere.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Even Is Excessive Data Exposure?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Simple definition:&lt;/strong&gt; The API gives you more data than you need to see.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Technical definition:&lt;/strong&gt; The backend queries &lt;code&gt;SELECT * FROM users&lt;/code&gt; and sends the entire database row to the frontend, even though the UI only displays 2 of the 15 columns.&lt;/p&gt;

&lt;p&gt;The scary part? You don't need broken authentication. You don't need SQL injection. You just need to &lt;strong&gt;look at the raw API response&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The 9 Endpoints Where I Always Find This
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. User Profile Endpoints
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;GET /api/users/{id}&lt;/code&gt; or &lt;code&gt;GET /api/users/me&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What to look for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;email&lt;/code&gt;, &lt;code&gt;phone&lt;/code&gt;, &lt;code&gt;address&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;password_hash&lt;/code&gt;, &lt;code&gt;salt&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;reset_token&lt;/code&gt;, &lt;code&gt;verify_token&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;two_fa_secret&lt;/code&gt;, &lt;code&gt;backup_codes&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;api_keys&lt;/code&gt;, &lt;code&gt;session_tokens&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Bug bounty example:&lt;/strong&gt; I once found &lt;code&gt;stripe_customer_id&lt;/code&gt; and &lt;code&gt;subscription_billing_cycle&lt;/code&gt; on a &lt;code&gt;/me&lt;/code&gt; endpoint. The company paid $500 because they considered it internal architecture exposure.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Search Endpoints
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;GET /api/search?q=john&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What to look for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full emails instead of truncated &lt;code&gt;j***@example.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Exact timestamps of last login&lt;/li&gt;
&lt;li&gt;Internal user IDs used for other API calls&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pro tip:&lt;/strong&gt; Even if you can't IDOR to other users, search your own email. The API might return extra fields on your own result that shouldn't be visible to you.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Registration / Signup Responses
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;POST /api/register&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What to look for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your password echoed back in plaintext (yes, this happens)&lt;/li&gt;
&lt;li&gt;Your session token in the response body&lt;/li&gt;
&lt;li&gt;Internal account flags like &lt;code&gt;"is_verified": false&lt;/code&gt;, &lt;code&gt;"requires_review": true&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Order History
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;GET /api/orders/12345&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What to look for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Credit card last4, expiry, billing zip&lt;/li&gt;
&lt;li&gt;Full shipping address&lt;/li&gt;
&lt;li&gt;Internal cost vs retail price (business logic exposure)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;refund_eligibility&lt;/code&gt; flags&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. File Upload Metadata
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;POST /api/upload&lt;/code&gt; → returns &lt;code&gt;file_id&lt;/code&gt; → &lt;code&gt;GET /api/files/{file_id}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What to look for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Internal S3 bucket paths (exposes infrastructure)&lt;/li&gt;
&lt;li&gt;Original filenames (could contain PII like &lt;code&gt;resume_ssn_123.pdf&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Uploader's IP address and user agent&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;file_permissions&lt;/code&gt; array showing who can access&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. GraphQL Endpoints (The Jackpot)
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;POST /graphql&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What to do:&lt;/strong&gt; Request fields you shouldn't see even on your own account:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;me&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;password_hash&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c"&gt;# ← try it&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;reset_token&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c"&gt;# ← try it&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;internal_notes&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c"&gt;# ← try it&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;admin_flags&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c"&gt;# ← try it&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Real bounty:&lt;/strong&gt; A bug hunter found &lt;code&gt;credit_card&lt;/code&gt; and &lt;code&gt;ssn&lt;/code&gt; fields exposed on the &lt;code&gt;/me&lt;/code&gt; query of a major credit bureau. $7,500 bounty.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Analytics &amp;amp; Dashboard Endpoints
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;GET /api/dashboard/stats&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What to look for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Other users' emails or IPs in event logs&lt;/li&gt;
&lt;li&gt;Database connection strings&lt;/li&gt;
&lt;li&gt;Debug arrays containing full request/response objects&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  8. Export / Download Endpoints
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;GET /api/export/users.csv&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What to look for:&lt;/strong&gt; If you can access this endpoint at all (auth bypass or misconfigured role), the CSV often contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full database columns including sensitive ones&lt;/li&gt;
&lt;li&gt;Password reset hashes&lt;/li&gt;
&lt;li&gt;2FA secrets (mangled or plain)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  9. PATCH / PUT Responses
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;PATCH /api/users/me&lt;/code&gt; (with empty body &lt;code&gt;{}&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this works:&lt;/strong&gt; When you send an update with no changes, some APIs still return the full updated object - which might contain fields you never had permission to read.&lt;/p&gt;




&lt;h2&gt;
  
  
  My 4-Step Testing Methodology
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Intercept Everything
&lt;/h3&gt;

&lt;p&gt;Stop trusting what you see in the browser/mobile app. Forward every request through Burp Suite, Caido, or ZAP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The raw response always tells the truth.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Build Your Keyword Radar
&lt;/h3&gt;

&lt;p&gt;I search responses for these strings (I keep this as a grep pattern):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;email|e-?mail|phone|mobile|telephone|address|location|
ssn|tax|tin|passport|license|driver|
birthday|dob|age|
password|pass|pwd|secret|token|jwt|api[_-]?key|apikey|
hash|salt|reset[_-]?token|verify[_-]?token|
credit[_-]?card|cc|cvv|expiry|stripe|paypal|
ip[_-]?address|user[_-]?agent|device[_-]?id|
internal[_-]?note|admin[_-]?note|flag|reason[_-]?code|
otp|mfa|two[_-]?fa|backup[_-]?code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Compare Responses Across IDs
&lt;/h3&gt;

&lt;p&gt;If you can change &lt;code&gt;?user_id=1&lt;/code&gt; to &lt;code&gt;?user_id=2&lt;/code&gt;, do it. But even without IDOR, compare:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authenticated vs unauthenticated&lt;/li&gt;
&lt;li&gt;Your low-privilege account vs a different low-privilege account&lt;/li&gt;
&lt;li&gt;Verbose param (&lt;code&gt;?verbose=true&lt;/code&gt;) vs normal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Tool tip:&lt;/strong&gt; Use Burp's &lt;strong&gt;Comparer&lt;/strong&gt; or the &lt;strong&gt;Diffy&lt;/strong&gt; extension to spot extra JSON keys.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Trigger Verbose Modes
&lt;/h3&gt;

&lt;p&gt;Add these parameters to every request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;?verbose&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
?debug&lt;span class="o"&gt;=&lt;/span&gt;1
?include_fields&lt;span class="o"&gt;=&lt;/span&gt;all
?format&lt;span class="o"&gt;=&lt;/span&gt;full
?fields&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;
?pretty&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
?show_internal&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>excessivedataexposure</category>
      <category>apipentesting</category>
      <category>apisecurity</category>
      <category>apidataexposure</category>
    </item>
    <item>
      <title>Broken User Authentication in APIs</title>
      <dc:creator>Abhinav Singwal</dc:creator>
      <pubDate>Sat, 06 Jun 2026 06:58:36 +0000</pubDate>
      <link>https://dev.to/abhinavsingwal/broken-user-authentication-in-apis-m1p</link>
      <guid>https://dev.to/abhinavsingwal/broken-user-authentication-in-apis-m1p</guid>
      <description>&lt;p&gt;Broken User Authentication ranks as the second most critical vulnerability in the OWASP API Security Top 10 for 2023. In bug bounty programs, authentication flaws often lead to account takeover, data breaches, and high-severity payouts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxy91245c927zdyog89c1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxy91245c927zdyog89c1.png" alt="Broken User Authentication in APIs" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unlike traditional web applications, APIs use stateless tokens, OAuth flows, and machine-to-machine communication patterns. This creates unique attack surfaces that many testers overlook. This guide covers the ten most critical API authentication vulnerabilities with practical testing techniques.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Makes API Authentication Different
&lt;/h2&gt;

&lt;p&gt;Standard web apps rely on session cookies and server-side state. APIs use tokens that carry all authentication information within the request itself. Every request must prove its identity independently.&lt;/p&gt;

&lt;p&gt;This stateless design introduces specific vulnerabilities. JWT tokens can be manipulated. Refresh tokens can be replayed. OAuth flows have multiple redirects where things go wrong. Understanding these differences is the first step to finding bugs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Ten Critical Vulnerabilities
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. JWT Algorithm Confusion
&lt;/h3&gt;

&lt;p&gt;JSON Web Tokens include an &lt;code&gt;alg&lt;/code&gt; header that tells the server which signing algorithm was used. When servers trust this header without strict validation, attackers can bypass signature verification.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;none&lt;/code&gt; algorithm attack works because some libraries accept unsigned tokens. Setting &lt;code&gt;alg: "none"&lt;/code&gt; removes the signature requirement entirely. The server processes the token as valid.&lt;/p&gt;

&lt;p&gt;The RS256 to HS256 confusion attack is more subtle. RS256 uses RSA private keys for signing and public keys for verification. HS256 uses a shared secret. If a server expects RS256 but receives HS256, it may verify the signature using the public key as an HMAC secret. Attackers who know the public key can forge valid tokens.&lt;/p&gt;

&lt;p&gt;Testing requires intercepting a valid JWT, modifying the &lt;code&gt;alg&lt;/code&gt; header, and sending the modified token to protected endpoints.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. JWT Key ID Injection
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;kid&lt;/code&gt; header specifies which key should verify the token. Servers often fetch this key from files, databases, or external URLs. When &lt;code&gt;kid&lt;/code&gt; is not sanitized, injection attacks become possible.&lt;/p&gt;

&lt;p&gt;Path traversal via &lt;code&gt;kid: "../../../dev/null"&lt;/code&gt; can read local files. If the server uses file contents as verification keys, attackers control the key.&lt;/p&gt;

&lt;p&gt;SQL injection in &lt;code&gt;kid&lt;/code&gt; works when servers query a database for the key. A payload like &lt;code&gt;' UNION SELECT 'public_key&lt;/code&gt; can return attacker-controlled values.&lt;/p&gt;

&lt;p&gt;SSRF attacks use &lt;code&gt;kid: "http://internal-service/secret"&lt;/code&gt; to force the server into fetching from attacker-specified locations.&lt;/p&gt;

&lt;p&gt;Testing requires modifying the &lt;code&gt;kid&lt;/code&gt; value to various injection payloads and observing server behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Weak JWT Secrets
&lt;/h3&gt;

&lt;p&gt;Many developers generate JWT secrets manually. Common choices include "secret", "changeme", "password", or simple strings. These are vulnerable to brute-force attacks.&lt;/p&gt;

&lt;p&gt;Hashcat with mode 16500 cracks JWT secrets. RockYou wordlist contains thousands of common secrets. Tools like jwt_tool and crackjwt automate this process.&lt;/p&gt;

&lt;p&gt;A secret with low entropy can be cracked in minutes on modern hardware. Even longer secrets that follow dictionary patterns are vulnerable.&lt;/p&gt;

&lt;p&gt;Testing involves capturing a valid JWT and attempting to crack its secret offline. No rate limits apply because the attack happens on your own machine.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Missing Token Expiration
&lt;/h3&gt;

&lt;p&gt;JWTs can include an &lt;code&gt;exp&lt;/code&gt; claim that defines expiration time. Without this claim, tokens remain valid forever. Some implementations set expiration to years in the future or never check it at all.&lt;/p&gt;

&lt;p&gt;An attacker who captures a token once can reuse it indefinitely. This is especially dangerous for tokens leaked in logs, browser history, or network traffic.&lt;/p&gt;

&lt;p&gt;Testing requires capturing a token, waiting for its supposed expiration, and attempting to reuse it. Also check if the &lt;code&gt;exp&lt;/code&gt; claim exists and whether the server rejects expired tokens.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Refresh Token Reuse Without Rotation
&lt;/h3&gt;

&lt;p&gt;Refresh tokens allow clients to obtain new access tokens without re-authenticating. The secure pattern is one-time use with rotation. Each refresh request returns a new refresh token and invalidates the old one.&lt;/p&gt;

&lt;p&gt;Without rotation, stolen refresh tokens remain valid forever. An attacker can generate unlimited access tokens from a single stolen refresh token.&lt;/p&gt;

&lt;p&gt;Testing involves using a refresh token to obtain new tokens, then using the same refresh token again. If the second request succeeds, rotation is missing.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Predictable Password Reset Tokens
&lt;/h3&gt;

&lt;p&gt;Password reset flows generate tokens sent via email or SMS. When these tokens follow predictable patterns, attackers can brute-force them.&lt;/p&gt;

&lt;p&gt;Common flaws include 4-digit or 6-digit numeric codes with no rate limiting. An attacker can try all 10,000 combinations in minutes.&lt;/p&gt;

&lt;p&gt;Time-based tokens using milliseconds or seconds since epoch are also predictable. If an attacker can guess the approximate reset request time, they can narrow the search space.&lt;/p&gt;

&lt;p&gt;Tokens returned in API responses during the reset request represent the most critical flaw. The attacker can simply read the token from the response body.&lt;/p&gt;

&lt;p&gt;Testing requires requesting multiple resets and analyzing token patterns. Check for sequential increases, timestamp encoding, or short numeric values.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. No Rate Limiting on Authentication Endpoints
&lt;/h3&gt;

&lt;p&gt;Login, OTP verification, password reset, and token issuance endpoints require rate limiting. Without it, brute-force attacks become feasible.&lt;/p&gt;

&lt;p&gt;Four-digit OTP codes need only 10,000 attempts. With no rate limits, this takes minutes. Credential stuffing using breached password lists becomes trivial.&lt;/p&gt;

&lt;p&gt;Rate limiting should apply per user, per IP address, and globally. It should also increase delays after repeated failures.&lt;/p&gt;

&lt;p&gt;Testing involves sending 100 or more rapid requests to authentication endpoints. Use Burp Intruder or a simple Python script. If all requests succeed, rate limiting is missing.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Verbose Error Messages Enabling Account Enumeration
&lt;/h3&gt;

&lt;p&gt;Authentication endpoints should return identical responses for all failure cases. When they differentiate, attackers can enumerate valid users.&lt;/p&gt;

&lt;p&gt;Different messages like "Password incorrect" versus "User not found" reveal whether an account exists. Registration endpoints that say "Email already registered" provide the same information.&lt;/p&gt;

&lt;p&gt;Response timing differences can also leak information. Checking an existing user might take longer because the server fetches the user record first.&lt;/p&gt;

&lt;p&gt;Testing requires comparing responses for known valid and known invalid inputs. Look for differences in status codes, response bodies, or response times.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. OAuth 2.0 Misconfiguration
&lt;/h3&gt;

&lt;p&gt;OAuth flows involve multiple redirects where tokens pass through the browser. Each redirect is an attack opportunity.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;redirect_uri&lt;/code&gt; parameter tells the OAuth provider where to send the authorization code. When validation is missing, attackers can set their own domain and steal codes.&lt;/p&gt;

&lt;p&gt;Open redirects in &lt;code&gt;redirect_uri&lt;/code&gt; allow attackers to leak codes via the Referer header. The code travels from the legitimate site to the attacker's site automatically.&lt;/p&gt;

&lt;p&gt;Missing CSRF protection on the &lt;code&gt;state&lt;/code&gt; parameter enables attackers to initiate flows and intercept responses. The &lt;code&gt;state&lt;/code&gt; parameter should be unpredictable and tied to the user session.&lt;/p&gt;

&lt;p&gt;Testing requires attempting to change &lt;code&gt;redirect_uri&lt;/code&gt; to external domains, open redirect endpoints, or localhost addresses.&lt;/p&gt;

&lt;h3&gt;
  
  
  10. Exposed API Keys in URLs and Client Code
&lt;/h3&gt;

&lt;p&gt;API keys in URLs appear in browser history, server logs, and Referer headers. Anyone with access to these logs can steal the key.&lt;/p&gt;

&lt;p&gt;Mobile applications and single-page apps often hardcode API keys in JavaScript or configuration files. These are trivially extractable.&lt;/p&gt;

&lt;p&gt;Debug endpoints, source maps, and public repositories are common leakage sources. Developers sometimes commit keys to GitHub despite best efforts.&lt;/p&gt;

&lt;p&gt;Testing involves checking network traffic, browser developer tools, JavaScript files, and public code repositories for exposed keys.&lt;/p&gt;

</description>
      <category>api</category>
      <category>apipentesting</category>
      <category>brokenuserauthentication</category>
      <category>apisecurity</category>
    </item>
    <item>
      <title>#XSS #CrossSiteScripting #XSSLABS #PortSwiggerLabsXSS</title>
      <dc:creator>Abhinav Singwal</dc:creator>
      <pubDate>Sat, 06 Jun 2026 05:35:41 +0000</pubDate>
      <link>https://dev.to/abhinavsingwal/xss-crosssitescripting-xsslabs-portswiggerlabsxss-2ioh</link>
      <guid>https://dev.to/abhinavsingwal/xss-crosssitescripting-xsslabs-portswiggerlabsxss-2ioh</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/abhinavsingwal/master-xss-the-practical-way-introducing-xss-labs-2p07" class="crayons-story__hidden-navigation-link"&gt;Master XSS the Practical Way: Introducing xss-labs&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/abhinavsingwal" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2914312%2F452f11ca-f061-4f95-a0f2-c76390b4e5c9.jpg" alt="abhinavsingwal profile" class="crayons-avatar__image" width="800" height="822"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/abhinavsingwal" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Abhinav Singwal
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Abhinav Singwal
                
              
              &lt;div id="story-author-preview-content-3754341" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/abhinavsingwal" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2914312%2F452f11ca-f061-4f95-a0f2-c76390b4e5c9.jpg" class="crayons-avatar__image" alt="" width="800" height="822"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Abhinav Singwal&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/abhinavsingwal/master-xss-the-practical-way-introducing-xss-labs-2p07" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;May 26&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/abhinavsingwal/master-xss-the-practical-way-introducing-xss-labs-2p07" id="article-link-3754341"&gt;
          Master XSS the Practical Way: Introducing xss-labs
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/tryhackme"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;tryhackme&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/xss"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;xss&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/xssrat"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;xssrat&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/hackthebox"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;hackthebox&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/abhinavsingwal/master-xss-the-practical-way-introducing-xss-labs-2p07#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>API Hacking: What is BOLA/IDOR?</title>
      <dc:creator>Abhinav Singwal</dc:creator>
      <pubDate>Sat, 06 Jun 2026 05:34:25 +0000</pubDate>
      <link>https://dev.to/abhinavsingwal/api-hacking-what-is-bolaidor-25f</link>
      <guid>https://dev.to/abhinavsingwal/api-hacking-what-is-bolaidor-25f</guid>
      <description>&lt;p&gt;Today I want to talk about one of the most common API vulnerabilities.&lt;/p&gt;

&lt;p&gt;It's called BOLA (Broken Object Level Authorization).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh0ioisjw2pkubv8fzgcx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh0ioisjw2pkubv8fzgcx.jpg" alt="Broken Object Level Authorization - API BOLA"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You might also know it as IDOR (Insecure Direct Object Reference).&lt;/p&gt;

&lt;p&gt;Don't let the fancy names scare you. It's actually very simple.&lt;/p&gt;

&lt;p&gt;Let me explain.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Imagine you live in an apartment building.&lt;/p&gt;

&lt;p&gt;Each apartment has a number: 101, 102, 103...&lt;/p&gt;

&lt;p&gt;Now imagine the building has no locks. Anyone can walk into any apartment.&lt;/p&gt;

&lt;p&gt;That's BOLA.&lt;/p&gt;

&lt;p&gt;The API says "here is apartment number 103" but never checks if you live there.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Real API Example
&lt;/h2&gt;

&lt;p&gt;Let's say you log into a shopping website.&lt;/p&gt;

&lt;p&gt;You want to see your order number 1001.&lt;/p&gt;

&lt;p&gt;The app sends this request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /api/orders/1001
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you see your order. Great.&lt;/p&gt;

&lt;p&gt;Now what happens if you change the number?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /api/orders/1002
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see someone else's order, that is BOLA.&lt;/p&gt;

&lt;p&gt;The API trusted you just because you asked. It never checked if the order belongs to you.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Does This Happen?
&lt;/h2&gt;

&lt;p&gt;Developers forget to add a simple check.&lt;/p&gt;

&lt;p&gt;They should ask: "Does user 123 own order 1002?"&lt;/p&gt;

&lt;p&gt;But sometimes they only ask: "Is user 123 logged in?"&lt;/p&gt;

&lt;p&gt;Being logged in is not enough. You also need permission to see that specific thing.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Hackers Find BOLA
&lt;/h2&gt;

&lt;p&gt;It is very simple. You just change numbers or IDs in the request.&lt;/p&gt;

&lt;p&gt;Look for these places:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GET /api/user/123&lt;/code&gt; -&amp;gt; try 124, 125, 126&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;POST /api/invoice&lt;/code&gt; with &lt;code&gt;{"invoice_id": 456}&lt;/code&gt; in body -&amp;gt; try 457&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DELETE /api/post/789&lt;/code&gt; -&amp;gt; try 788, 787&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/api/download?file=report_1.pdf&lt;/code&gt; -&amp;gt; try report_2.pdf&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also try UUIDs like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/api/user/550e8400-e29b-41d4-a716-446655440000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change one letter or number. Sometimes it still works.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Test Method (2 Accounts)
&lt;/h2&gt;

&lt;p&gt;This is how I test for BOLA:&lt;/p&gt;

&lt;p&gt;Step 1: Create two accounts (Account A and Account B)&lt;br&gt;
Step 2: Login as Account A, find an order ID or user ID&lt;br&gt;
Step 3: Copy the request&lt;br&gt;
Step 4: Login as Account B&lt;br&gt;
Step 5: Paste the request and change the ID to Account A's ID&lt;/p&gt;

&lt;p&gt;If you see Account A's data while logged in as Account B, you found BOLA.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Protect Your API (For Developers)
&lt;/h2&gt;

&lt;p&gt;If you build APIs, remember this rule:&lt;/p&gt;

&lt;p&gt;Never trust the user. Always check permission.&lt;/p&gt;

&lt;p&gt;Every time someone asks for an object, ask two questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Is the user logged in?&lt;/li&gt;
&lt;li&gt;Does this user own the object?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For extra safety, don't use simple numbers like 123. Use random UUIDs. But even then, still check permissions.&lt;/p&gt;

&lt;p&gt;Found this helpful? Leave a like and follow for more API hacking posts.&lt;/p&gt;

&lt;p&gt;Questions? Drop a comment below.&lt;/p&gt;

</description>
      <category>api</category>
      <category>cybersecurity</category>
      <category>bola</category>
      <category>apipentesting</category>
    </item>
    <item>
      <title>Cross Site Scripting Labs #XSS</title>
      <dc:creator>Abhinav Singwal</dc:creator>
      <pubDate>Fri, 05 Jun 2026 06:51:04 +0000</pubDate>
      <link>https://dev.to/abhinavsingwal/cross-site-scripting-labs-xss-4amk</link>
      <guid>https://dev.to/abhinavsingwal/cross-site-scripting-labs-xss-4amk</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/abhinavsingwal/master-xss-the-practical-way-introducing-xss-labs-2p07" class="crayons-story__hidden-navigation-link"&gt;Master XSS the Practical Way: Introducing xss-labs&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/abhinavsingwal" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2914312%2F452f11ca-f061-4f95-a0f2-c76390b4e5c9.jpg" alt="abhinavsingwal profile" class="crayons-avatar__image" width="800" height="822"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/abhinavsingwal" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Abhinav Singwal
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Abhinav Singwal
                
              
              &lt;div id="story-author-preview-content-3754341" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/abhinavsingwal" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2914312%2F452f11ca-f061-4f95-a0f2-c76390b4e5c9.jpg" class="crayons-avatar__image" alt="" width="800" height="822"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Abhinav Singwal&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/abhinavsingwal/master-xss-the-practical-way-introducing-xss-labs-2p07" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;May 26&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/abhinavsingwal/master-xss-the-practical-way-introducing-xss-labs-2p07" id="article-link-3754341"&gt;
          Master XSS the Practical Way: Introducing xss-labs
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/tryhackme"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;tryhackme&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/xss"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;xss&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/xssrat"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;xssrat&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/hackthebox"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;hackthebox&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/abhinavsingwal/master-xss-the-practical-way-introducing-xss-labs-2p07#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>CVE-2021-3163: Stored XSS Concerns in Quill Rich Text Editor</title>
      <dc:creator>Abhinav Singwal</dc:creator>
      <pubDate>Fri, 05 Jun 2026 06:47:54 +0000</pubDate>
      <link>https://dev.to/abhinavsingwal/cve-2021-3163-stored-xss-concerns-in-quill-rich-text-editor-1ikd</link>
      <guid>https://dev.to/abhinavsingwal/cve-2021-3163-stored-xss-concerns-in-quill-rich-text-editor-1ikd</guid>
      <description>&lt;p&gt;Text editors are commonly used in web applications for comments, blog posts, support tickets, documentation systems, and messaging platforms. Because they process user-controlled content, security issues affecting these editors can have significant consequences.&lt;/p&gt;

&lt;p&gt;One publicly discussed issue involving Quill is CVE-2021-3163, which was assigned to a potential Stored Cross-Site Scripting (XSS) vulnerability in Quill versions prior to 1.3.7.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs2jhuudjws4ir003fquo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs2jhuudjws4ir003fquo.png" alt=" " width="388" height="130"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is the Issue?
&lt;/h2&gt;

&lt;p&gt;The vulnerability report describes a situation where specially crafted HTML content could result in JavaScript execution when rendered by applications using Quill.&lt;/p&gt;

&lt;p&gt;The issue specifically involved handling of user-supplied HTML content within the editor. Since the content is stored and later viewed by other users, the impact falls into the category of Stored XSS.&lt;/p&gt;

&lt;p&gt;It is worth noting that the vulnerability has been publicly disputed, with discussions around whether the behavior originates from browser parsing behavior or from Quill itself. Regardless of the debate, applications processing untrusted HTML should treat such reports seriously.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Stored XSS Is Dangerous
&lt;/h2&gt;

&lt;p&gt;Stored XSS is generally considered more severe than reflected XSS because the malicious content is saved by the application and automatically delivered to future visitors.&lt;/p&gt;

&lt;p&gt;Potential impacts include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Session hijacking&lt;/li&gt;
&lt;li&gt;Account takeover&lt;/li&gt;
&lt;li&gt;Unauthorized actions on behalf of users&lt;/li&gt;
&lt;li&gt;Phishing attacks&lt;/li&gt;
&lt;li&gt;Defacement of application content&lt;/li&gt;
&lt;li&gt;Theft of sensitive information accessible through the browser&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Typical Vulnerable Pattern
&lt;/h2&gt;

&lt;p&gt;Applications often take editor output and directly insert it into the DOM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;databaseContent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;article&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the content contains unsafe HTML, the browser may interpret and execute it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Secure Approach
&lt;/h2&gt;

&lt;p&gt;Before rendering user-generated HTML, sanitize it.&lt;/p&gt;

&lt;p&gt;Example using DOMPurify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"dompurify.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cleanHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;DOMPurify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sanitize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;databaseContent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;article&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cleanHTML&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This removes dangerous elements and attributes before the content reaches the browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example Quill Integration
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;quill&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Quill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#editor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;snow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;quill&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If this HTML is later displayed elsewhere in the application, it should be sanitized before rendering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Affected Versions
&lt;/h2&gt;

&lt;p&gt;Reportedly affected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Quill &amp;lt; 1.3.7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Mitigation
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Upgrade to the latest supported version of Quill.&lt;/li&gt;
&lt;li&gt;Sanitize all user-generated HTML.&lt;/li&gt;
&lt;li&gt;Apply Content Security Policy (CSP).&lt;/li&gt;
&lt;li&gt;Validate content on both client and server sides.&lt;/li&gt;
&lt;li&gt;Regularly review third-party dependencies.&lt;/li&gt;
&lt;li&gt;Avoid trusting rich-text editor output by default.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Security Takeaway
&lt;/h2&gt;

&lt;p&gt;Rich text editors provide convenience, but they also introduce risk because they handle complex HTML content generated by users. CVE-2021-3163 serves as a reminder that any feature allowing HTML input should be carefully reviewed, sanitized, and monitored.&lt;/p&gt;

&lt;p&gt;Even when a vulnerability is disputed, security teams should evaluate the behavior, understand the potential impact on their environment, and implement appropriate defensive controls.&lt;/p&gt;




&lt;p&gt;Author: Abhinav Singwal&lt;/p&gt;

&lt;p&gt;&lt;a href="https://linktr.ee/abhinavsingwal" rel="noopener noreferrer"&gt;https://linktr.ee/abhinavsingwal&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cve20213163</category>
      <category>storedxss</category>
      <category>xss</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>Missing rate limiting on login pages is a critical vulnerability I find constantly during shopping site audits. This post explains how attackers exploit it, how to test for it, and exactly how to fix it. A must-read for any e-commerce developer or security.</title>
      <dc:creator>Abhinav Singwal</dc:creator>
      <pubDate>Thu, 04 Jun 2026 00:57:51 +0000</pubDate>
      <link>https://dev.to/abhinavsingwal/missing-rate-limiting-on-login-pages-is-a-critical-vulnerability-i-find-constantly-during-shopping-g6k</link>
      <guid>https://dev.to/abhinavsingwal/missing-rate-limiting-on-login-pages-is-a-critical-vulnerability-i-find-constantly-during-shopping-g6k</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/abhinavsingwal/why-your-shopping-sites-missing-rate-limit-is-a-disaster-waiting-to-happen-2679" class="crayons-story__hidden-navigation-link"&gt;Why Your Shopping Site's Missing Rate Limit Is a Disaster Waiting to Happen&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/abhinavsingwal" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2914312%2F452f11ca-f061-4f95-a0f2-c76390b4e5c9.jpg" alt="abhinavsingwal profile" class="crayons-avatar__image" width="800" height="822"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/abhinavsingwal" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Abhinav Singwal
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Abhinav Singwal
                
              
              &lt;div id="story-author-preview-content-3815090" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/abhinavsingwal" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2914312%2F452f11ca-f061-4f95-a0f2-c76390b4e5c9.jpg" class="crayons-avatar__image" alt="" width="800" height="822"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Abhinav Singwal&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/abhinavsingwal/why-your-shopping-sites-missing-rate-limit-is-a-disaster-waiting-to-happen-2679" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jun 4&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/abhinavsingwal/why-your-shopping-sites-missing-rate-limit-is-a-disaster-waiting-to-happen-2679" id="article-link-3815090"&gt;
          Why Your Shopping Site's Missing Rate Limit Is a Disaster Waiting to Happen
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/security"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;security&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ecommerce"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ecommerce&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/business"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;business&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/abhinavsingwal/why-your-shopping-sites-missing-rate-limit-is-a-disaster-waiting-to-happen-2679#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>ecommerce</category>
      <category>business</category>
      <category>website</category>
      <category>shopping</category>
    </item>
    <item>
      <title>Why Your Shopping Site's Missing Rate Limit Is a Disaster Waiting to Happen</title>
      <dc:creator>Abhinav Singwal</dc:creator>
      <pubDate>Thu, 04 Jun 2026 00:56:56 +0000</pubDate>
      <link>https://dev.to/abhinavsingwal/why-your-shopping-sites-missing-rate-limit-is-a-disaster-waiting-to-happen-2679</link>
      <guid>https://dev.to/abhinavsingwal/why-your-shopping-sites-missing-rate-limit-is-a-disaster-waiting-to-happen-2679</guid>
      <description>&lt;p&gt;You have built a beautiful e-commerce platform. Customers love the smooth checkout. Your product images load instantly. But there is a silent killer hiding in your login form.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa6pq74n6up5ttjru8mbf.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa6pq74n6up5ttjru8mbf.webp" alt="Login Screen" width="400" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The lack of rate limiting on authentication attempts.&lt;/p&gt;

&lt;p&gt;I run a security audit business focused on shopping websites. The number one vulnerability I find is not SQL injection or cross-site scripting. It is the ability to try passwords unlimited times. No blocks. No delays. No CAPTCHA.&lt;/p&gt;

&lt;p&gt;This article explains why this matters, how attackers exploit it, and what you need to fix today.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem in Plain English
&lt;/h2&gt;

&lt;p&gt;Rate limiting means restricting how many requests a user or IP address can make in a specific time window.&lt;/p&gt;

&lt;p&gt;Without rate limiting on your login endpoint, an attacker can send one thousand password guesses per second. Your server will happily process each one. After a few minutes, the attacker has tried one hundred thousand passwords. After an hour, millions.&lt;/p&gt;

&lt;p&gt;Your customer`s account falls to a dictionary attack. Their stored credit card gets drained. Their saved addresses get changed to a drop location. And you get the chargeback nightmare.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Attackers Exploit This
&lt;/h2&gt;

&lt;p&gt;There are three common attack patterns against shopping sites with no login rate limiting.&lt;/p&gt;

&lt;p&gt;Credential stuffing is the most dangerous. Attackers take username and password pairs leaked from other data breaches. They feed these into your login endpoint automatically. Many people reuse passwords across sites. The attacker now owns those accounts on your platform.&lt;/p&gt;

&lt;p&gt;Brute force attacks are simpler but still effective. Attackers try common passwords like password123 or winter2024 against many usernames. Without rate limiting, they will eventually succeed on accounts with weak credentials.&lt;/p&gt;

&lt;p&gt;Username enumeration is a privacy leak. When the login response differs slightly for valid versus invalid usernames, attackers can discover which email addresses have accounts on your site. This information sells to spammers and phishers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real Example From a Recent Audit
&lt;/h2&gt;

&lt;p&gt;I tested a mid-sized fashion retailer last month. Their API login endpoint had zero restrictions. I wrote a simple twenty-line Python script. It tried one thousand passwords per minute from a single IP address.&lt;/p&gt;

&lt;p&gt;Within eight minutes, I cracked three customer accounts. Two used their first name as the password. One used welcome123. All three had saved payment methods.&lt;/p&gt;

&lt;p&gt;I reported this as critical severity. The fix was trivial to implement. But the client had been vulnerable for over two years.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Shopping Sites Are Prime Targets
&lt;/h2&gt;

&lt;p&gt;Shopping sites hold three things attackers want.&lt;/p&gt;

&lt;p&gt;Payment card data. Even tokenized cards can be used for fraudulent purchases if the account is compromised.&lt;/p&gt;

&lt;p&gt;Shipping addresses. Attackers use these to build identity profiles or send unsolicited packages.&lt;/p&gt;

&lt;p&gt;Order history. This reveals spending habits, income indicators, and product preferences used for targeted scams.&lt;/p&gt;

&lt;p&gt;A compromised shopping account is a complete identity and payment package. No wonder attackers target these sites relentlessly.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Test Your Own Site
&lt;/h2&gt;

&lt;p&gt;Run this simple manual test right now.&lt;/p&gt;

&lt;p&gt;Open an incognito window and go to your login page. Enter a valid customer email address. Type a wrong password. Submit the form. Repeat this twenty times as fast as you can click.&lt;/p&gt;

&lt;p&gt;Does your site ever stop you? Do you see a CAPTCHA? Does the login button become disabled temporarily? Does the page tell you to wait?&lt;/p&gt;

&lt;p&gt;If nothing changes after twenty failed attempts, you are vulnerable.&lt;/p&gt;

&lt;p&gt;For a more thorough test, use Burp Suite Intruder or write a short curl loop.&lt;/p&gt;

&lt;p&gt;curl -X POST &lt;a href="https://yoursite.com/login" rel="noopener noreferrer"&gt;https://yoursite.com/login&lt;/a&gt; \&lt;br&gt;
  -d "email=&lt;a href="mailto:customer@example.com"&gt;customer@example.com&lt;/a&gt;&amp;amp;password=wrongguess"&lt;/p&gt;

&lt;p&gt;Run that one hundred times. If you still get the same invalid credentials response without any lockout, you have confirmed the vulnerability.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Technical Fixes That Work
&lt;/h2&gt;

&lt;p&gt;Implementing rate limiting is not difficult. Here are the specific controls that protect your customers.&lt;/p&gt;

&lt;p&gt;Per-IP rate limiting blocks an IP address after a certain number of failed attempts. Start with ten attempts per minute. After that, return HTTP 429 Too Many Requests. Do not even process the authentication attempt.&lt;/p&gt;

&lt;p&gt;Per-account rate limiting protects a specific customer account from being targeted by many different IP addresses. Allow five failed attempts per hour on a single account. After the fifth failure, lock the account for fifteen minutes or require email verification to unlock.&lt;/p&gt;

&lt;p&gt;Progressive delays increase the response time after each failure. After three failures, add a one-second delay. After five failures, add a five-second delay. This does not block the user but makes automated guessing impossibly slow.&lt;/p&gt;

&lt;p&gt;CAPTCHA after N failures stops bots while letting legitimate users through. Use reCAPTCHA v3 which runs invisibly in the background. Most real users never see it, but automated scripts get blocked.&lt;/p&gt;

&lt;p&gt;Web Application Firewall rules can provide a stopgap if you cannot modify application code. Configure your WAF to block IPs that exceed a threshold of login requests per minute.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Bypasses and How to Prevent Them
&lt;/h2&gt;

&lt;p&gt;Attackers will try to circumvent your rate limiting. You must protect against these bypass methods as well.&lt;/p&gt;

&lt;p&gt;IP rotation uses a botnet of thousands of residential proxies. Each IP makes only a few attempts. Per-IP limits alone fail against this. You need per-account rate limiting to stop distributed attacks.&lt;/p&gt;

&lt;p&gt;Parameter pollution appends debug=true or similar parameters to the request. Some applications apply rate limits only to the clean URL but not the parameterized version. Normalize all request parameters before applying rate limits.&lt;/p&gt;

&lt;p&gt;Different endpoints sometimes have separate rate limits. Attackers may target the API login endpoint while you protected only the web login. Apply consistent rate limiting across all authentication endpoints including login, password reset, and API authentication.&lt;/p&gt;

&lt;p&gt;Header spoofing sends X-Forwarded-For headers to fake IP addresses. If your rate limiting trusts this header without validation, attackers can bypass it. Extract the real client IP from the lowest trusted layer, typically the connection source address.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing This Up in Your Security Report
&lt;/h2&gt;

&lt;p&gt;When you find missing rate limiting on a client site, here is how to document it professionally.&lt;/p&gt;

&lt;p&gt;Title: Missing Rate Limiting on Login Endpoint&lt;/p&gt;

&lt;p&gt;Severity: High&lt;/p&gt;

&lt;p&gt;Endpoint: POST /api/v1/login&lt;/p&gt;

&lt;p&gt;Description: The application accepts an unlimited number of failed authentication attempts to the same user account from the same IP address. No CAPTCHA, delay, or account lockout mechanism is present.&lt;/p&gt;

&lt;p&gt;Proof of Concept: One hundred consecutive login requests with incorrect passwords were sent over thirty seconds. Each request returned HTTP 200 with a generic Invalid credentials message. The account remained accessible for correct password entry throughout the test.&lt;/p&gt;

&lt;p&gt;Impact: An attacker can perform automated brute force or credential stuffing attacks leading to account takeover. Compromised accounts can be used for fraudulent purchases, gift card draining, and personal data theft.&lt;/p&gt;

&lt;p&gt;Remediation: Implement per-IP rate limiting of ten attempts per minute returning HTTP 429 after the limit. Implement per-account rate limiting of five failed attempts per hour with a fifteen minute temporary lockout. Add CAPTCHA after three consecutive failures.&lt;/p&gt;

&lt;p&gt;References: OWASP ASVS V2.1.2, CWE-307&lt;/p&gt;

&lt;h2&gt;
  
  
  The Business Case for Fixing This
&lt;/h2&gt;

&lt;p&gt;Your development team might say this is low priority. Here is what to tell them.&lt;/p&gt;

&lt;p&gt;One account takeover leads to an average loss of two hundred fifty dollars in fraudulent transactions plus fifty dollars in chargeback fees. If you have one hundred thousand customer accounts and a one percent annual takeover rate, that is two hundred fifty thousand dollars in direct losses.&lt;/p&gt;

&lt;p&gt;Payment card networks increase fees for merchants with high fraud rates. Your compliance auditor will flag missing rate limiting during PCI DSS assessment. Insurance providers may deny breach claims if basic controls like rate limiting were missing.&lt;/p&gt;

&lt;p&gt;The fix takes a competent developer four hours to implement and test. The cost of not fixing it is orders of magnitude higher.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>ecommerce</category>
      <category>business</category>
    </item>
    <item>
      <title>Weak password policies allowing brute force attacks.

#E-Commerce #WebDevelopment #CyberSecurity</title>
      <dc:creator>Abhinav Singwal</dc:creator>
      <pubDate>Wed, 03 Jun 2026 11:34:57 +0000</pubDate>
      <link>https://dev.to/abhinavsingwal/weak-password-policies-allowing-brute-force-attackse-commerce-webdevelopment-cybersecurity-13f6</link>
      <guid>https://dev.to/abhinavsingwal/weak-password-policies-allowing-brute-force-attackse-commerce-webdevelopment-cybersecurity-13f6</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/abhinavsingwal/weak-password-policies-no-rate-limiting-the-account-takeover-crisis-in-e-commerce-2d5b" class="crayons-story__hidden-navigation-link"&gt;Weak Password Policies + No Rate Limiting: The Account Takeover Crisis in E-Commerce&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/abhinavsingwal" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2914312%2F452f11ca-f061-4f95-a0f2-c76390b4e5c9.jpg" alt="abhinavsingwal profile" class="crayons-avatar__image" width="800" height="822"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/abhinavsingwal" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Abhinav Singwal
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Abhinav Singwal
                
              
              &lt;div id="story-author-preview-content-3810641" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/abhinavsingwal" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2914312%2F452f11ca-f061-4f95-a0f2-c76390b4e5c9.jpg" class="crayons-avatar__image" alt="" width="800" height="822"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Abhinav Singwal&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/abhinavsingwal/weak-password-policies-no-rate-limiting-the-account-takeover-crisis-in-e-commerce-2d5b" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jun 3&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/abhinavsingwal/weak-password-policies-no-rate-limiting-the-account-takeover-crisis-in-e-commerce-2d5b" id="article-link-3810641"&gt;
          Weak Password Policies + No Rate Limiting: The Account Takeover Crisis in E-Commerce
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ecommerce"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ecommerce&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/business"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;business&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/cybersecurity"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;cybersecurity&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/abhinavsingwal/weak-password-policies-no-rate-limiting-the-account-takeover-crisis-in-e-commerce-2d5b#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Weak Password Policies + No Rate Limiting: The Account Takeover Crisis in E-Commerce</title>
      <dc:creator>Abhinav Singwal</dc:creator>
      <pubDate>Wed, 03 Jun 2026 11:31:47 +0000</pubDate>
      <link>https://dev.to/abhinavsingwal/weak-password-policies-no-rate-limiting-the-account-takeover-crisis-in-e-commerce-2d5b</link>
      <guid>https://dev.to/abhinavsingwal/weak-password-policies-no-rate-limiting-the-account-takeover-crisis-in-e-commerce-2d5b</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Most shopping websites allow users to set passwords like &lt;code&gt;password123&lt;/code&gt; or &lt;code&gt;admin&lt;/code&gt;. At the same time, they do not limit how many login attempts can be made per minute. This combination creates a critical vulnerability: attackers can try thousands of password guesses per hour until they find the correct one.&lt;/p&gt;

&lt;p&gt;Account takeover via brute force is not theoretical. It happens daily across small and medium e-commerce stores. The result is stolen payment information, fraudulent orders, and angry customers who blame the merchant.&lt;/p&gt;

&lt;p&gt;If your shopping website allows unlimited login attempts and accepts weak passwords, your customer accounts are essentially unprotected.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz1kjs2hzhu6xsqvdyfom.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz1kjs2hzhu6xsqvdyfom.jpeg" alt=" " width="282" height="179"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How Attackers Exploit This Combination
&lt;/h2&gt;

&lt;p&gt;The exploitation process follows a simple, automated workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The attacker obtains a list of email addresses. These may come from previous data breaches, OSINT, or simple guessing.&lt;/li&gt;
&lt;li&gt;The attacker uses a tool like Hydra, Burp Suite Intruder, or a custom Python script to send login requests.&lt;/li&gt;
&lt;li&gt;The tool cycles through the top 1000 most common passwords against each email address.&lt;/li&gt;
&lt;li&gt;Because there is no rate limiting, all 1000 attempts complete in minutes.&lt;/li&gt;
&lt;li&gt;Because the password policy is weak, common passwords like &lt;code&gt;qwerty123&lt;/code&gt; or &lt;code&gt;welcome&lt;/code&gt; are actually valid.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Within hours, the attacker compromises dozens or hundreds of accounts.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real-World Attack Scenarios on Shopping Sites
&lt;/h2&gt;

&lt;p&gt;The following attack vectors are common in e-commerce environments:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Customer Account Brute Force&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
An attacker targets a list of customer email addresses. Upon successful login, the attacker gains access to saved credit cards, shipping addresses, order history, and stored gift cards. This data can be used for identity theft or direct financial fraud.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Admin Account Brute Force&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Many shopping platforms use predictable admin panel URLs like &lt;code&gt;/admin&lt;/code&gt; or &lt;code&gt;/administrator&lt;/code&gt;. Attackers attempt common credentials such as &lt;code&gt;admin:password&lt;/code&gt;, &lt;code&gt;admin:admin&lt;/code&gt;, or &lt;code&gt;storename:storename&lt;/code&gt;. A compromised admin account allows the attacker to issue mass refunds, download the entire customer database, or deface the website.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gift Card and Loyalty Point Brute Force&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If a shopping website allows unlimited balance checks on gift card numbers or loyalty accounts, attackers can brute force valid numbers. Predictable gift card code patterns worsen this risk.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Coupon Code Brute Force&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Attackers can discover active discount codes by brute forcing common patterns such as &lt;code&gt;SAVE10&lt;/code&gt;, &lt;code&gt;SAVE20&lt;/code&gt;, &lt;code&gt;WELCOME15&lt;/code&gt;, or &lt;code&gt;SUMMER2024&lt;/code&gt;. This leads to revenue loss and promotion abuse.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why E-Commerce Platforms Are Particularly Vulnerable
&lt;/h2&gt;

&lt;p&gt;Shopping websites have unique characteristics that make them more susceptible to this vulnerability than banks or social media platforms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Frictionless Checkout Priority&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
E-commerce businesses prioritize speed. Adding CAPTCHA or login delays is seen as hurting conversion rates. Security is often deprioritized until a breach occurs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reliance on Payment Processors&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Many merchants assume the payment gateway handles all fraud prevention. Payment processors monitor transaction fraud, not login attempts. The login system is entirely the merchant's responsibility.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use of Insecure Templates&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Small to medium stores frequently use unmodified open-source platforms or cheap templates. These often ship with default password policies and no rate limiting configured.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Third-Party Account Integration&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Shopping websites that allow social login still maintain traditional login endpoints. Attackers target the weaker traditional endpoint.&lt;/p&gt;


&lt;h2&gt;
  
  
  Step-by-Step Testing Methodology
&lt;/h2&gt;

&lt;p&gt;You should test your own website responsibly. The following methodology assumes you have permission to test.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Assess Password Policy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Attempt to register or change a password using these values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;password&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;123456&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;qwerty&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aaaaaaaa&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;password123&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;No numbers or symbols only&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If any of these are accepted, your policy is weak.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Test for Rate Limiting&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Send 100 consecutive login requests with incorrect credentials to the same account. Use a simple bash loop or a tool like Burp Suite Intruder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;i &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;1..100&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://yourstore.com/login &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"email":"victim@example.com","password":"wrongpassword"}'&lt;/span&gt;
  &lt;span class="nb"&gt;sleep &lt;/span&gt;0.1
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If all 100 requests return the same response (e.g., &lt;code&gt;invalid credentials&lt;/code&gt;), there is no rate limiting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Check for Account Lockout&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After 10 to 20 failed attempts, the account should lock temporarily. If you can still attempt logins after 50 attempts without any lockout message, lockout is absent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Test IP-Based vs User-Based Rate Limiting&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Repeat the 100 attempts from a different IP address. If the second IP can also attempt 100 times without delay, rate limiting is missing entirely.&lt;/p&gt;




&lt;h2&gt;
  
  
  Sample Proof of Concept
&lt;/h2&gt;

&lt;p&gt;The following Python script demonstrates a minimal brute force test. This is for authorized security testing only.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;

&lt;span class="n"&gt;target_email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;customer@example.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;password_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;password&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;123456&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwerty&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;admin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;welcome&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;password123&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://target-shop.com/api/login&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;password_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;target_email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;password&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Trying &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Success! Password is &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Minimal delay, often ineffective
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On a vulnerable site, this script finds a valid password within seconds.&lt;/p&gt;




&lt;h2&gt;
  
  
  Business Impact: Beyond the Hype
&lt;/h2&gt;

&lt;p&gt;The impact of brute force account takeover on a shopping website includes the following business consequences.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Financial Loss from Fraudulent Orders&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Compromised accounts are used to place orders using saved payment methods. The original customer disputes the charge. The merchant absorbs chargeback fees, product loss, and payment processor penalties.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Customer Churn and Reputation Damage&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
News of a breach spreads quickly on social media and review platforms. Customers lose trust and move to competitors. Small merchants rarely recover their reputation after a publicized account takeover incident.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Support Overload&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
After a breach, customer support teams receive hundreds of password reset requests and fraud reports. This strains limited support resources.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Legal and Compliance Exposure&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Data breach notification laws may require the merchant to disclose the incident to affected customers and regulators. Failure to disclose leads to fines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gift Card and Loyalty Point Theft&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If gift card balances are accessible via login, attackers drain stored value. The merchant must reissue funds or face customer lawsuits.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Fix It: Actionable Recommendations
&lt;/h2&gt;

&lt;p&gt;Implement the following controls in order of priority.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Priority 1: Enforce a Strong Password Policy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Require a minimum of 8 characters. Require at least three of the four following character types: uppercase letters, lowercase letters, numbers, and symbols. Maintain a blocklist of the top 1000 most common passwords from breaches. Reject passwords that include the user's email prefix or common patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Priority 2: Implement Rate Limiting&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Allow a maximum of 5 login attempts per 15 minutes per user account. Allow a maximum of 10 login attempts per 15 minutes per IP address across all accounts. Return a standard HTTP 429 Too Many Requests response when limits are exceeded.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Priority 3: Add Progressive Delays&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After 3 failed attempts, introduce a 2-second delay before allowing another attempt. After 7 failed attempts, increase the delay to 10 seconds. Delays make brute force economically unviable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Priority 4: Implement Account Lockout&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Temporarily lock the account for 15 minutes after 10 consecutive failed login attempts. Send an email alert to the account owner when lockout occurs. Require password reset after 20 cumulative failed attempts over 24 hours.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Priority 5: Add CAPTCHA&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Present a CAPTCHA after 3 failed login attempts from the same IP or account. Use reCAPTCHA v3 or hCaptcha to minimize friction while blocking automation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Priority 6: Monitor and Alert&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Log all failed login attempts including timestamp, IP address, and user agent. Configure alerts for more than 10 failed attempts on a single account in 5 minutes. Review logs weekly for brute force patterns.&lt;/p&gt;

</description>
      <category>ecommerce</category>
      <category>business</category>
      <category>webdev</category>
      <category>cybersecurity</category>
    </item>
  </channel>
</rss>
