{"id":510,"date":"2026-04-04T00:42:15","date_gmt":"2026-04-04T00:42:15","guid":{"rendered":"https:\/\/quantusintel.group\/osint\/blog\/2026\/04\/04\/how-a-public-anon-key-led-to-full-database-compromise\/"},"modified":"2026-04-04T00:42:15","modified_gmt":"2026-04-04T00:42:15","slug":"how-a-public-anon-key-led-to-full-database-compromise","status":"publish","type":"post","link":"https:\/\/quantusintel.group\/osint\/blog\/2026\/04\/04\/how-a-public-anon-key-led-to-full-database-compromise\/","title":{"rendered":"How a Public Anon Key Led to Full Database Compromise"},"content":{"rendered":"<p>In March 2026, I conducted a penetration test against a social media-style web application (referred to as <a href=\"https:\/\/targetapp.io\/\">TargetApp.io<\/a>). The engagement was authorized by the platform\u2019s owner and spanned approximately two weeks. The most critical vulnerability was discovered on the second day. While the test began as a traditional black-box assessment, simulating an external attacker with no insider knowledge, it evolved into what industry practitioners classify as a credentialed black box or grey box assessment.<\/p>\n<p>This distinction is important. During the engagement, I discovered a publicly exposed API key embedded in client-side code. While the key itself was intended to be public (a anon key), its existence allowed me to perform authenticated queries against the backend database. In effect, I was operating with partial knowledge; a non-public asset (the key) was leveraged to conduct unauthenticated queries that should have been restricted. This shaped the depth of testing and ultimately led to the discovery of a critical database misconfiguration.<\/p>\n<p>This article provides a comprehensive walkthrough of the engagement, including methodology, detailed findings, the credentialed factor\u2019s role in testing, and key takeaways for developers and security practitioners.<\/p>\n<h3>Engagement Overview<\/h3>\n<h3>Scope and Objectives<\/h3>\n<p>The test targeted the primary domain (targetapp.io) and its associated subdomains. The engagement was conducted as a black-box assessment with a credentialed\/grey box twist: I had no prior access to source code, architecture documentation, or privileged credentials, but I did obtain a publicly exposed API key that enabled backend queries. This placed the test in a unique category.<\/p>\n<figure><img data-opt-id=771569372  fetchpriority=\"high\" decoding=\"async\" alt=\"\" src=\"https:\/\/cdn-images-1.medium.com\/max\/1024\/1*r_Q0Y0aI63auazpZknBWEA.png\" \/><figcaption>ApiKey sitting in Client-Side.<\/figcaption><\/figure>\n<p>In this case, The anon Key was discovered during standard reconnaissance (visible in browser network traffic). While it was intended to be public, its misuse potential transformed the assessment from purely unauthenticated testing to a scenario where I could perform credentialed queries against the backend, without ever holding a user\u00a0account.<\/p>\n<h3>Methodology<\/h3>\n<p>I followed a structured methodology aligned with industry-standard frameworks, including:<\/p>\n<ul>\n<li>OWASP Testing Guide\u200a\u2014\u200afor web application vulnerability classification<\/li>\n<li>PTES (Penetration Testing Execution Standard)\u200a\u2014\u200afor structured phases and reporting<\/li>\n<\/ul>\n<p>The engagement was divided into the following phases:<\/p>\n<ol>\n<li>Reconnaissance<\/li>\n<li>Architecture Analysis<\/li>\n<li>Authentication &amp; Authorization Testing<\/li>\n<li>API Security\u00a0Testing<\/li>\n<li>Database Security Assessment<\/li>\n<li>Client-Side Security\u00a0Testing<\/li>\n<li>Business Logic\u00a0Testing<\/li>\n<\/ol>\n<h3>The Credentialed Factor: Why It\u00a0Matters<\/h3>\n<p>In traditional black-box testing, the tester has no credentials and operates entirely as an unauthenticated user. However, modern web applications often expose non-public assets, API keys, backend references, and internal endpoints through client-side code. An attacker with basic reconnaissance skills can extract these assets and use them to probe deeper into the application\u2019s infrastructure.<\/p>\n<p>This test began as a standard black-box engagement. During reconnaissance, I observed that the application made direct client-side requests to a backend database provider. Embedded in these requests was a public anon key, a credential intended to allow unauthenticated client applications to interact with the database under controlled conditions. While the key itself is meant to be public, its presence allowed me to perform queries that should have been restricted by proper Row Level Security (RLS) policies.<\/p>\n<p>With this key, I effectively transitioned from an unauthenticated external attacker to a credentialed user with partial backend access. This is the essence of a credentialed black box or grey box test: operating with partial knowledge that an attacker could realistically obtain, then using that knowledge to uncover deeper vulnerabilities.<\/p>\n<p>This approach ultimately revealed the most critical finding of the engagement: RLS was disabled on multiple tables, meaning The anon Key provided unrestricted read and write access to the entire user database.<\/p>\n<h3>Detailed Findings<\/h3>\n<p>A total of seven findings were identified during this engagement, ranging from Informational to Critical severity. The credentialed factor played a direct role in uncovering F-01, the most severe\u00a0finding.<\/p>\n<h3>F-01: Database RLS Disabled\u200a\u2014\u200aUnauthenticated PII Access (CRITICAL)<\/h3>\n<p>Severity\u200a\u2014\u200aCritical<\/p>\n<p>CVSS Score 9.8 (AV:N\/AC:L\/PR:N\/UI:N\/S:U\/C:H\/I:H\/A:H)<\/p>\n<p>Affected Componentsprofiles, follows, watchlists tables in the backend\u00a0database<\/p>\n<p>Discovery Method: Credentialed\/grey box \u2013 leveraging public anon key discovered during reconnaissance<\/p>\n<h4>Description<\/h4>\n<p>The application uses a Backend-as-a-Service (BaaS) provider for its database and authentication layer. During standard reconnaissance, I observed that the application made direct client-side requests to the backend provider. Embedded in these requests\u00a0were:<\/p>\n<ul>\n<li>The full backend project reference URL<\/li>\n<li>The public anon API\u00a0key<\/li>\n<li>API endpoint structures<\/li>\n<\/ul>\n<p>With this information, specifically the anon Key, I began probing the backend API directly. What I discovered was that Row Level Security (RLS) was completely disabled on at least three critical tables: profiles, follows, and watchlists. RLS is a security feature that restricts which rows a user can access based on SQL policies. When disabled, any request containing the public anon key can perform unrestricted read and write operations on these\u00a0tables.<\/p>\n<p>Because I now possessed the anon key (a credential, although a public one), I was operating in a credentialed capacity, even though I had never created a user account or authenticated in the traditional sense. This partial knowledge allowed me to move beyond surface-level testing and directly query the backend database.<\/p>\n<h4>Technical Evidence<\/h4>\n<p>Using only the public anon Key extracted from browser network traffic, I executed the following unauthenticated requests:<\/p>\n<p>Read All User Profiles:<\/p>\n<pre>GET \/rest\/v1\/profiles?select=*<br \/>Host: [redacted].supabase.co<br \/>apikey: [public anon key]<\/pre>\n<p>Response: Full user records returned, including:<\/p>\n<ul>\n<li>User IDs, usernames, display names, bios, avatar URLs, and countries<\/li>\n<li>Stripe customer IDs and subscription IDs<\/li>\n<li>Subscription tier, status, renewal\u00a0dates<\/li>\n<li>Admin privilege flags<\/li>\n<li>Account creation dates and activity\u00a0metrics<\/li>\n<li>Theme preferences and personalization settings<\/li>\n<\/ul>\n<p>Write to Any User\u00a0Profile:<\/p>\n<pre>PATCH \/rest\/v1\/profiles?id=eq.[target_user_id]<br \/>Host: [redacted].supabase.co<br \/>apikey: [public anon key]<br \/>Content-Type: application\/json<br \/><br \/>{\"display_name\": \"hijacked\"}<\/pre>\n<p>Response: 204 No Content \u2013 modification successful<\/p>\n<figure><img data-opt-id=771569372  fetchpriority=\"high\" decoding=\"async\" alt=\"\" src=\"https:\/\/cdn-images-1.medium.com\/max\/1024\/1*xjf6D1_ZzsZ3ufgJsTuq8w.png\" \/><\/figure>\n<figure><img data-opt-id=771569372  decoding=\"async\" alt=\"\" src=\"https:\/\/cdn-images-1.medium.com\/max\/1024\/1*H3jU45_4tveYcHxZvQfPRQ.png\" \/><\/figure>\n<h4>Data Exposed<\/h4>\n<p>1.1 Data Category: Personally Identifiable Information (PII)<\/p>\n<p>Examples: Personally Identifiable Information (PII): Usernames, bios, location, avatar\u00a0URLs<\/p>\n<p>Risk: Privacy violation, user profiling<\/p>\n<p>1.2 Data Category: Payment &amp;\u00a0Billing,<\/p>\n<p>Examples: Stripe customer IDs, subscription details, Revenue Cat\u00a0IDs,<\/p>\n<p>Risk: Financial fraud, targeted support\u00a0scams<\/p>\n<p>1.3 Data Category: Privilege Data<\/p>\n<p>Examples: Admin\u00a0flags<\/p>\n<p>Risk: Identification of high-value targets<\/p>\n<p>1.4 Data Category: Social\u00a0Graph<\/p>\n<p>Examples: Follower\/following relationships<\/p>\n<p>Risk: Mapping user\u00a0networks<\/p>\n<p>1.5 Data Category: Private\u00a0Content<\/p>\n<p>Examples: Watchlist entries marked as\u00a0private<\/p>\n<p>Risk: Exposure of non-public preferences<\/p>\n<figure><img data-opt-id=771569372  decoding=\"async\" alt=\"\" src=\"https:\/\/cdn-images-1.medium.com\/max\/1024\/1*V3NgqWFQsigAW2D24nqHXA.png\" \/><figcaption>Full Breach of Confidentiality and Integrity App\u00a0wide.<\/figcaption><\/figure>\n<h4>Impact Analysis<\/h4>\n<p>This finding represents a complete breach of confidentiality and integrity. Approximately under 20 users were registered on the platform at the time of testing, all of whom had their data exposed. An unauthenticated attacker who discovers the anon key (as I did)\u00a0could:<\/p>\n<ul>\n<li>Harvest all user PII for identity theft or social engineering<\/li>\n<li>Identify paying customers and admin accounts for targeted\u00a0attacks<\/li>\n<li>Modify any user\u2019s profile information, potentially defacing profiles or disrupting accounts<\/li>\n<li>Map complete social graphs and private user\u00a0behavior<\/li>\n<\/ul>\n<p>The credentialed factor was critical to this discovery. Without the anon Key, I would have been limited to testing the application&#8217;s public-facing interface. With it, operating in a grey box capacity, I was able to directly probe the backend and uncover the complete lack of access controls.<\/p>\n<h4>Remediation Steps<\/h4>\n<ol>\n<li>Immediate: Enable RLS on all tables in the Supabase dashboard.<\/li>\n<li>Immediate: Create RLS policies that restrict SELECT operations to authenticated users, viewing only their own\u00a0records.<\/li>\n<li>Immediate: Revoke write permissions from the public anon key; ensure the key is scoped to the minimum required permissions.<\/li>\n<li>Audit all remaining tables for the same misconfiguration, and assume all tables are exposed until verified.<\/li>\n<li>Review backend logs to determine if unauthorized access occurred prior to this finding being reported.<\/li>\n<li>Consider rotating the anon key, noting that this will require updating all client-side references.<\/li>\n<li>Engage legal counsel to assess breach notification obligations.<\/li>\n<\/ol>\n<h3>F-02: Open Redirect\u200a\u2014\u200aMultiple Unvalidated Parameters (MEDIUM)<\/h3>\n<p>Severity Medium<br \/>CVSS Score 6.1 (AV:N\/AC:L\/PR:N\/UI:R\/S:C\/C:L\/I:L\/A:N)<br \/>Affected Endpoints: Multiple login and callback endpoints<br \/>Discovery Method: Traditional black-box testing<br \/>Status Open\u200a\u2014\u200aRemediation required<\/p>\n<h4>Description<\/h4>\n<p>The application contains unvalidated redirect parameters on multiple endpoints. Six distinct redirect parameters were confirmed to be vulnerable: next, goto, redirect_uri, callback, continue, and url. None of these parameters validates that the destination URL belongs to the application&#8217;s domain before performing the redirect. The breadth of affected parameters indicates that redirect validation is absent at the framework or middleware level\u2014this is not an isolated bug in a single code\u00a0path.<\/p>\n<h4>Proof of\u00a0Concept<\/h4>\n<p>Each of the following parameters successfully redirected to an external domain (https:\/\/evil.com):<\/p>\n<pre>https:\/\/targetapp.io\/login?next=https:\/\/evil.com<br \/>https:\/\/targetapp.io\/auth\/callback?goto=https:\/\/evil.com<br \/>https:\/\/targetapp.io\/oauth\/confirm?redirect_uri=https:\/\/evil.com<br \/>https:\/\/targetapp.io\/verify?callback=https:\/\/evil.com<br \/>https:\/\/targetapp.io\/account\/link?continue=https:\/\/evil.com<br \/>https:\/\/targetapp.io\/share?url=https:\/\/evil.com<\/pre>\n<h4>Attack Scenario<\/h4>\n<p>A realistic attack chain exploiting this vulnerability, now made more dangerous by the information obtained through credentialed testing:<\/p>\n<ol>\n<li>Attacker discovers backend infrastructure (as I did via F-03) during reconnaissance.<\/li>\n<li>Attacker registers a lookalike domain (e.g., targetapp-account.com) and hosts a convincing fake login page that mirrors the exposed backend structure.<\/li>\n<li>Attacker crafts a phishing email containing the malicious URL:<br \/>https:\/\/targetapp.io\/login?next=https:\/\/targetapp-account.com\/steal<\/li>\n<li>The victim sees a legitimate <a href=\"https:\/\/targetapp.io\/\">targetapp.io<\/a> URL in the link and trusts\u00a0it.<\/li>\n<li>Victim logs in successfully on the real login\u00a0page.<\/li>\n<li>The victim is silently redirected to the attacker\u2019s site, which now appears authentic because it leverages knowledge of the exposed\u00a0backend.<\/li>\n<\/ol>\n<h4>Impact Analysis<\/h4>\n<p>Medium severity. The vulnerability enables phishing attacks that are significantly more convincing than standard phishing because the initial URL is a legitimate domain. When combined with the backend exposure discovered during credentialed testing, an attacker can create a highly convincing fake environment that mirrors the real application\u2019s infrastructure.<\/p>\n<figure><img data-opt-id=771569372  decoding=\"async\" alt=\"\" src=\"https:\/\/cdn-images-1.medium.com\/max\/1024\/1*sMY5Cr4njQYwA6xL6makIA.png\" \/><figcaption>Redirects to https:\/\/evil.com<\/figcaption><\/figure>\n<h4>Remediation Steps<\/h4>\n<ol>\n<li>Implement an allowlist of permitted redirect destinations. Only allow relative paths or explicitly approved same-origin URLs.<\/li>\n<li>Reject or sanitize any redirect parameter that contains an absolute URL with an external\u00a0domain.<\/li>\n<li>Default to a safe location (e.g., homepage) when an invalid redirect target is detected.<\/li>\n<li>Add automated tests that verify external URLs in redirect parameters result in safe fallbacks rather than open redirects.<\/li>\n<\/ol>\n<h3>F-03: No Rate Limiting on Account Registration (MEDIUM)<\/h3>\n<p>Severity Medium<br \/>CVSS Score 5.3 (AV:N\/AC:L\/PR:N\/UI:N\/S:U\/C:N\/I:L\/A:L)<br \/>Affected EndpointPOST \/auth\/sign-up<br \/>Discovery Method: Traditional black-box testing<br \/>StatusOpen \u2013 Remediation required<\/p>\n<h4>Description<\/h4>\n<p>The account registration endpoint does not implement rate limiting. During testing, ten concurrent registration requests using distinct email addresses and usernames all returned HTTP 200 OK responses with no throttling, CAPTCHA challenge, or blocking response. An attacker can automate mass account creation with no restrictions.<\/p>\n<h4>Technical Evidence<\/h4>\n<p>A script was used to submit ten registration requests in rapid succession:<\/p>\n<pre>for i in {1..10}; do<br \/>  curl -X POST https:\/\/targetapp.io\/auth\/sign-up <br \/>    -H \"Content-Type: application\/json\" <br \/>    -d \"{\"email\":\"user$i@example.com\",\"password\":\"Password123!\"}\" &amp;<br \/>done<br \/>wait<\/pre>\n<p>Result: All ten requests returned 200 OK. No 429 Too Many Requests Responses were observed.<\/p>\n<figure><img data-opt-id=771569372  decoding=\"async\" alt=\"\" src=\"https:\/\/cdn-images-1.medium.com\/max\/1024\/1*SgWrFm17xGnvTr80ONhMzg.png\" \/><figcaption>Just for reference I won\u2019t show all\u00a010.<\/figcaption><\/figure>\n<h4>Attack Scenarios<\/h4>\n<ol>\n<li>Spam &amp; Abuse Attacker creates thousands of accounts to post spam, fake reviews, or abusive\u00a0content.<\/li>\n<\/ol>\n<p>2. Sybil Attack: Mass account creation to manipulate voting, ratings, or social trust\u00a0metrics.<\/p>\n<p>3. Ban Evasion: Banned users can instantly re-register with a new email\u00a0address.<\/p>\n<p>4. Resource Exhaustion: Mass registrations fill the user database, potentially incurring unexpected costs.<\/p>\n<h4>Remediation Steps<\/h4>\n<ol>\n<li>Implement rate limiting on POST \/auth\/sign-up (e.g., 5 registrations per IP per\u00a0hour).<\/li>\n<li>Add CAPTCHA to the registration flow to prevent automated submissions.<\/li>\n<li>Enforce email verification before new accounts can access sensitive features.<\/li>\n<li>Monitor registration patterns for anomalies indicating automated abuse.<\/li>\n<\/ol>\n<h3>F-04: Backend Provider Reference Exposed Client-Side (LOW)<\/h3>\n<p>Severity Low <br \/>Category: Information Disclosure<br \/>Affected Component Client-side JavaScript \/ Network traffic<br \/>Discovery Method: Traditional black-box reconnaissance<br \/>Role in Credentialed Testing: This exposure provided the anon key and backend reference that enabled credentialed probing<\/p>\n<h4>Description<\/h4>\n<p>The application makes direct client-side requests to its BaaS backend, exposing the full project reference URL in browser network traffic during normal usage. This\u00a0reveals:<\/p>\n<ul>\n<li>The backend provider and technology stack<\/li>\n<li>The specific project identifier<\/li>\n<li>API endpoint structure and internal column\u00a0names<\/li>\n<li>The public anon API key \u2013 the credential that enabled further\u00a0testing<\/li>\n<\/ul>\n<h4>Evidence<\/h4>\n<p>Observed in browser Developer Tools Network\u00a0tab:<\/p>\n<pre>GET \/rest\/v1\/profiles?select=theme_preference,subscription_tier&amp;id=eq.[redacted]<br \/>Host: [redacted].supabase.co<br \/>Authorization: Bearer [redacted]<br \/>apiKey: [redacted]  &lt;--The credential that enabled grey box testing<\/pre>\n<h4>Impact Analysis<\/h4>\n<p>Low severity individually, but critical in context. This finding alone does not directly expose sensitive data. However, it provided the partial knowledge (the anon key) that allowed me to transition from an unauthenticated black-box test to a credentialed grey box assessment. Without this exposure, the critical RLS misconfiguration (F-01) might not have been discovered.<\/p>\n<h4>Remediation Steps<\/h4>\n<ol>\n<li>Route API calls server-side through a proxy or API routes to abstract the backend provider and project reference from client-side traffic.<\/li>\n<li>Audit RLS policies on all exposed tables to ensure proper access controls.<\/li>\n<li>Consider using a custom domain for the backend project to obscure the project reference ID.<\/li>\n<li>Ensure the public anon Key is scoped to the minimum required permissions, and RLS policies enforce those permissions.<\/li>\n<\/ol>\n<h3>F-05: Missing HTTP Security Headers\u00a0(LOW)<\/h3>\n<p>Severity Low<br \/>Category Security Misconfiguration<br \/>Discovery Method: Traditional black-box testing<\/p>\n<h4>Description<\/h4>\n<p>The application does not return standard HTTP security headers in its responses, including:<\/p>\n<ul>\n<li>Content-Security-Policy<\/li>\n<li>X-Frame-Options<\/li>\n<li>X-Content-Type-Options<\/li>\n<li>Strict-Transport-Security<\/li>\n<\/ul>\n<h4>Impact Analysis<\/h4>\n<p>No direct exploitation is possible from missing headers alone. However, their absence removes browser-enforced mitigations that would reduce the impact of other vulnerabilities.<\/p>\n<h4>Remediation Steps<\/h4>\n<p>Add the following headers to all responses:<\/p>\n<pre>Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'<br \/>X-Frame-Options: DENY<br \/>X-Content-Type-Options: nosniff<br \/>Strict-Transport-Security: max-age=63072000; includeSubDomains; preload<\/pre>\n<h3>F-06 &amp; F-07: Unused Subdomains and DNS Records (INFORMATIONAL)<\/h3>\n<p>Severity Informational<br \/>Affected Assets: Multiple subdomains pointing to cloud infrastructure<br \/>Discovery Method: DNS enumeration (reconnaissance phase)<\/p>\n<h4>Description<\/h4>\n<p>During DNS enumeration, multiple subdomains were found with valid DNS A records pointing to cloud infrastructure IPs but with no active deployment attached. Subdomain takeover was confirmed not possible due to A records rather than CNAME delegation.<\/p>\n<h4>Affected Subdomains<\/h4>\n<ul>\n<li>api.targetapp.io<\/li>\n<li>blog.targetapp.io<\/li>\n<li>account.targetapp.io<\/li>\n<\/ul>\n<h4>Remediation Steps<\/h4>\n<p>Remove DNS A records for unused subdomains or deploy placeholder pages if reserved for future use. Conduct periodic DNS\u00a0audits.<\/p>\n<h3>Lessons Learned: The Credentialed Factor in\u00a0Practice<\/h3>\n<h3>For Developers<\/h3>\n<ol>\n<li>Treat all client-side credentials as compromised. The anon key may be &#8220;public&#8221; by design, but if RLS is disabled, it becomes a skeleton key to your database. Always enforce RLS policies regardless of key\u00a0scope.<\/li>\n<li>Never assume client-side exposure is harmless. The exposure of backend references and API keys in client-side code provided the partial knowledge that escalated this test from black box to credentialed grey box. An attacker will do the\u00a0same.<\/li>\n<li>Defense in depth applies to credentials. Even if a key is meant to be public, layer additional controls: RLS, rate limiting, IP restrictions, and server-side proxying.<\/li>\n<li>Redirect validation must be systemic. Open redirects are not isolated bugs; they often indicate a lack of validation at the framework level. Implement centralized redirect validation.<\/li>\n<\/ol>\n<h3>For Security Practitioners<\/h3>\n<ol>\n<li>Embrace the credentialed factor. When you discover a credential during reconnaissance, use it. Operating with partial knowledge, even when that credential is \u201cpublic\u201d, can reveal vulnerabilities that pure black-box testing might\u00a0miss.<\/li>\n<li>Document the shift in test methodology. Clearly articulate when a test evolves from black box to grey box. This transparency helps clients understand how findings were discovered and why they are\u00a0credible<\/li>\n<li>Combine findings for greater impact. The backend exposure (F-03) enabled the RLS misconfiguration discovery (F-01). Open redirects (F-04) become more dangerous when an attacker can build a convincing fake environment using exposed backend\u00a0details.<\/li>\n<\/ol>\n<h3>For Organizations<\/h3>\n<ol>\n<li>Understand the risk of client-side exposure. Modern applications routinely embed API keys, endpoints, and internal references in client-side code. These are not secrets, they are assets that must be secured with proper backend controls.<\/li>\n<li>Conduct regular security assessments with varying methodologies. A purely black-box test might not probe backend APIs with discovered credentials. Consider credentialed and grey box testing to simulate realistic attacker behavior.<\/li>\n<li>Prioritize critical findings immediately. The RLS misconfiguration was reported verbally before the final written report. Accelerated communication is essential for urgent\u00a0issues.<\/li>\n<\/ol>\n<h3>What I\u2019d Do Differently Next\u00a0Time?<\/h3>\n<p>If I ran this test again, I\u2019d automate backend API fuzzing as soon as I found the anon key; I spent too long manually probing. Also, I\u2019d check for RLS misconfigurations before testing business logic, since that yielded the highest impact\u00a0finding.<\/p>\n<h3>Conclusion<\/h3>\n<p>This penetration test began as a standard black-box engagement but evolved into a credentialed black box \/ grey box assessment when a public anon key, exposed client-side, was leveraged to probe backend systems. That partial knowledge led to the discovery of a critical failure in access control: Row Level Security was disabled on multiple database tables, granting unrestricted read and write access to the entire user database.<\/p>\n<p>The credentialed factor was essential to this discovery. Without the key, I would have remained an unauthenticated external attacker, limited to testing the application\u2019s public interface. With it, I could directly query the backend and uncover a vulnerability that exposed every user\u2019s PII, payment details, and private\u00a0content.<\/p>\n<p>This engagement underscores several key principles:<\/p>\n<ul>\n<li>Client-side exposure is not harmless; it provides the partial knowledge that enables deeper testing and real-world attacks.<\/li>\n<li>Credentials, even \u201cpublic\u201d ones, must be paired with proper access controls; RLS is non-negotiable for database security.<\/li>\n<li>Defense in depth matters; security headers, rate limiting, and redirect validation add layers that reduce the impact of other vulnerabilities.<\/li>\n<li>Methodology matters; clearly documenting when a test transitions from black box to grey box provides transparency and helps clients understand the realistic attacker perspective.<\/li>\n<\/ul>\n<p>All findings were delivered with actionable remediation steps. The most critical issue was reported verbally before the final written report to accelerate remediation. Following these recommendations will significantly improve the security posture of the application and protect its users from data exposure, phishing attacks, and automated abuse.<\/p>\n<blockquote><p><strong>This article is based on an actual penetration test and is shared for educational and portfolio purposes. All identifying information has been redacted to maintain confidentiality.<\/strong><\/p><\/blockquote>\n<p><img data-opt-id=574357117  decoding=\"async\" src=\"https:\/\/medium.com\/_\/stat?event=post.clientViewed&amp;referrerSource=full_rss&amp;postId=a58f065d367e\" width=\"1\" height=\"1\" alt=\"\" \/><\/p>\n<hr \/>\n<p><a href=\"https:\/\/osintteam.blog\/how-a-public-anon-key-led-to-full-database-compromise-a58f065d367e\">How a Public Anon Key Led to Full Database Compromise<\/a> was originally published in <a href=\"https:\/\/osintteam.blog\/\">OSINT Team<\/a> on Medium, where people are continuing the conversation by highlighting and responding to this story.<\/p>","protected":false},"excerpt":{"rendered":"<p>In March 2026, I conducted a penetration test against a social media-style web application (referred to as TargetApp.io). The engagement was authorized by the platform\u2019s owner and spanned approximately two weeks. The most critical vulnerability was discovered on the second day. While the test began as a traditional black-box assessment, simulating an external attacker with &#8230; <a title=\"How a Public Anon Key Led to Full Database Compromise\" class=\"read-more\" href=\"https:\/\/quantusintel.group\/osint\/blog\/2026\/04\/04\/how-a-public-anon-key-led-to-full-database-compromise\/\" aria-label=\"Read more about How a Public Anon Key Led to Full Database Compromise\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":511,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-510","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/quantusintel.group\/osint\/wp-json\/wp\/v2\/posts\/510","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/quantusintel.group\/osint\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/quantusintel.group\/osint\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/quantusintel.group\/osint\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/quantusintel.group\/osint\/wp-json\/wp\/v2\/comments?post=510"}],"version-history":[{"count":0,"href":"https:\/\/quantusintel.group\/osint\/wp-json\/wp\/v2\/posts\/510\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/quantusintel.group\/osint\/wp-json\/wp\/v2\/media\/511"}],"wp:attachment":[{"href":"https:\/\/quantusintel.group\/osint\/wp-json\/wp\/v2\/media?parent=510"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/quantusintel.group\/osint\/wp-json\/wp\/v2\/categories?post=510"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/quantusintel.group\/osint\/wp-json\/wp\/v2\/tags?post=510"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}