<?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: Abir Joshi</title>
    <description>The latest articles on DEV Community by Abir Joshi (@joshiabir).</description>
    <link>https://dev.to/joshiabir</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2208384%2F0e0ab6c3-1469-42bb-8085-cfa689c17025.jpg</url>
      <title>DEV Community: Abir Joshi</title>
      <link>https://dev.to/joshiabir</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/joshiabir"/>
    <language>en</language>
    <item>
      <title>Your employees are pasting secrets into ChatGPT &amp; Co-pilot &amp; Claude &amp; DeepSeek? Here's how to actually stop it.</title>
      <dc:creator>Abir Joshi</dc:creator>
      <pubDate>Fri, 17 Jul 2026 00:09:33 +0000</pubDate>
      <link>https://dev.to/joshiabir/your-employees-are-pasting-secrets-into-chatgpt-co-pilot-claude-deepseek-heres-how-to-5956</link>
      <guid>https://dev.to/joshiabir/your-employees-are-pasting-secrets-into-chatgpt-co-pilot-claude-deepseek-heres-how-to-5956</guid>
      <description>&lt;p&gt;Ask any engineering manager whether their team pastes code into ChatGPT and you'll get&lt;br&gt;
a nervous laugh. The honest answer is &lt;em&gt;constantly&lt;/em&gt; — a stack trace here, a config file&lt;br&gt;
there, "just cleaning up this SQL." Most of it is harmless. Some of it carries an AWS&lt;br&gt;
key, a database password, or a customer's PII straight to a third-party model.&lt;/p&gt;

&lt;p&gt;I've spent the last while looking at how teams try to control this, and most of the&lt;br&gt;
common approaches quietly fail. Here's what doesn't work, what does, and why.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this isn't a normal DLP problem
&lt;/h2&gt;

&lt;p&gt;Traditional DLP watches email, file shares, and cloud storage. An AI prompt leak skips&lt;br&gt;
all of them: the data goes from a browser tab to an AI provider's API over HTTPS and&lt;br&gt;
never touches the channels legacy DLP inspects.&lt;/p&gt;

&lt;p&gt;It's also invisible after the fact. Once a prompt is sent there's no sent-mail copy, no&lt;br&gt;
uploaded-file record. If you didn't catch it at the moment of submission, you have no&lt;br&gt;
idea it happened. Prevention has to live &lt;em&gt;in the browser&lt;/em&gt;, or it doesn't happen at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  The approaches that don't hold up
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Blocking AI tools outright.&lt;/strong&gt; Employees just switch to their phone or a personal
laptop. You lose the productivity and keep the risk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network proxies / CASBs.&lt;/strong&gt; They can see the domain but struggle to inspect encrypted
prompt &lt;em&gt;content&lt;/em&gt; without heavy MITM infrastructure — and they don't understand a DOCX
dropped into a chat window.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Policy + training.&lt;/strong&gt; Sets expectations, stops nothing in the moment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Post-hoc SaaS scanners.&lt;/strong&gt; Find the exposure &lt;em&gt;after&lt;/em&gt; the data already left. Good for
audit, useless for prevention.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What actually works: intercept in the browser
&lt;/h2&gt;

&lt;p&gt;The only place you can reliably read a prompt is where it's typed. A managed browser&lt;br&gt;
extension can patch the page's network calls, read the prompt (and any attached files)&lt;br&gt;
&lt;em&gt;before&lt;/em&gt; they send, scan against your DLP rules, and block anything that matches — all&lt;br&gt;
client-side, in well under a second, with no proxy and no rerouted traffic.&lt;/p&gt;

&lt;p&gt;That's the model I've become convinced is right, and it's the approach&lt;br&gt;
&lt;a href="https://slopfence.com/platform" rel="noopener noreferrer"&gt;Slopfence&lt;/a&gt; takes — a browser-native AI security platform&lt;br&gt;
that runs on ChatGPT, Claude, Gemini and Copilot, extracts text from uploaded Office/PDF&lt;br&gt;
files, and blocks or redacts on the ten built-in policies plus your own rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  A rollout that takes an afternoon
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Deploy the extension via Chrome/Edge GPO or your MDM (Jamf/Intune), pre-configured.&lt;/li&gt;
&lt;li&gt;Start with default policies (SSNs, cards, AWS keys, PII) active on install.&lt;/li&gt;
&lt;li&gt;Run &lt;strong&gt;alert-only&lt;/strong&gt; for a week to baseline what your team is really sending.&lt;/li&gt;
&lt;li&gt;Flip high-severity rules to block; scope stricter rules to Finance, Legal, Eng.&lt;/li&gt;
&lt;li&gt;Review the audit trail and tune custom rules and document fingerprints.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you want the deeper version of this playbook — the control matrix, the alert-vs-block&lt;br&gt;
tradeoffs, and the rollout checklist — I wrote it up here:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://slopfence.com/guides/stop-secrets-leaking-to-ai" rel="noopener noreferrer"&gt;how to stop secrets leaking to AI&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;The uncomfortable truth is that your team has already adopted AI. The question is whether&lt;br&gt;
you can see what they're sending it — and step in before the leak, not after.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>privacy</category>
      <category>security</category>
    </item>
    <item>
      <title>API Middleware – a self-hosted API gateway with DLP scanning built in Laravel 11</title>
      <dc:creator>Abir Joshi</dc:creator>
      <pubDate>Thu, 02 Apr 2026 13:12:48 +0000</pubDate>
      <link>https://dev.to/joshiabir/api-middleware-a-self-hosted-api-gateway-with-dlp-scanning-built-in-laravel-11-2g25</link>
      <guid>https://dev.to/joshiabir/api-middleware-a-self-hosted-api-gateway-with-dlp-scanning-built-in-laravel-11-2g25</guid>
      <description>&lt;p&gt;got tired of paying for managed API gateways that didn't let me inspect the data flowing through them. So I built &lt;strong&gt;API Middleware&lt;/strong&gt; — open source, self-hosted, one command to run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub: &lt;a href="https://github.com/joshiabir/theapimiddleware" rel="noopener noreferrer"&gt;https://github.com/joshiabir/theapimiddleware&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;API Middleware sits between your clients and your backend services. Instead of clients hitting your backend directly, they hit the gateway, which:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Routes traffic based on the incoming domain&lt;/li&gt;
&lt;li&gt;Scans request and response bodies for sensitive data (DLP)&lt;/li&gt;
&lt;li&gt;Enforces rate limits (global and per-user)&lt;/li&gt;
&lt;li&gt;Checks authentication before forwarding&lt;/li&gt;
&lt;li&gt;Logs every request with timing — asynchronously, so it never slows down the client&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything is configured through a web admin dashboard. No config files, no redeployments — change a DLP rule and it's live in seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;Two Laravel 11 apps sharing one MySQL database:&lt;/p&gt;

&lt;h3&gt;
  
  
  fiona — the gateway
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request → policyControl middleware → DLP scan → HTTP proxy → DLP scan → Response
                                                                ↓
                                                         Queue job (logging)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The middleware chain in &lt;code&gt;policyControl&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Looks up the domain in &lt;code&gt;domain_routings&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Finds the cluster and API config for the URL&lt;/li&gt;
&lt;li&gt;Applies policies: rate limits, auth, IP filtering, honeypot detection&lt;/li&gt;
&lt;li&gt;If all checks pass, forwards the request&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The proxy uses Laravel's &lt;code&gt;Http::send()&lt;/code&gt; with the original headers and method intact. After the response comes back, DLP runs again on the response body. Log writes go to a queue job so they never add latency.&lt;/p&gt;

&lt;h3&gt;
  
  
  plucker-app — the admin dashboard
&lt;/h3&gt;

&lt;p&gt;Built with Livewire v3 and Jetstream. 54 Livewire components cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Domain routing management&lt;/li&gt;
&lt;li&gt;Cluster and API configuration&lt;/li&gt;
&lt;li&gt;DLP rule editor (keywords, regex patterns, bypass URLs)&lt;/li&gt;
&lt;li&gt;Request log viewer with filtering and CSV export&lt;/li&gt;
&lt;li&gt;Security incident feed&lt;/li&gt;
&lt;li&gt;OAuth login (Google, GitHub, Microsoft)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The database-driven config is the key design decision: fiona reads policy state from the DB on every request, plucker writes to it. No signal needed between the two apps — policy changes are instant.&lt;/p&gt;

&lt;h2&gt;
  
  
  The DLP engine
&lt;/h2&gt;

&lt;p&gt;Each domain can have multiple DLP policies. The scanner chains them all against the request or response body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Keyword match&lt;/span&gt;
&lt;span class="nv"&gt;$redacted_body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;preg_replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;preg_quote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$policy&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'[redacted]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Regex pattern match  &lt;/span&gt;
&lt;span class="nv"&gt;$pattern&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'~'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$policy&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'~'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$redacted_body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;preg_replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$pattern&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'[redacted]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Actions per policy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;alert&lt;/code&gt; — log the match, pass the original body through&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;redact&lt;/code&gt; — replace matches with &lt;code&gt;[redacted]&lt;/code&gt; in the forwarded body&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;block&lt;/code&gt; — return 403 if any match is found&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Invalid regex patterns are caught and skipped gracefully so one bad rule doesn't break everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/joshiabir/theapimiddleware.git
&lt;span class="nb"&gt;cd &lt;/span&gt;theapimiddleware
./setup.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The setup script installs Docker if it's not present (macOS via Homebrew, Ubuntu/Debian/Fedora via package manager), generates app keys and DB passwords, writes &lt;code&gt;.env&lt;/code&gt;, and starts all containers.&lt;/p&gt;

&lt;p&gt;Two services come up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gateway (fiona): &lt;code&gt;http://localhost:8000&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Admin dashboard (plucker-app): &lt;code&gt;http://localhost:8001&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;Full PestPHP test suite using SQLite in-memory — no database needed to run tests.&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="nb"&gt;cd &lt;/span&gt;fiona &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ./vendor/bin/pest
&lt;span class="nb"&gt;cd &lt;/span&gt;plucker-app &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ./vendor/bin/pest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Covers: DLP service logic, policy middleware enforcement, proxy flow, Livewire dashboard components.&lt;/p&gt;




&lt;p&gt;Open to feedback on the architecture, especially the shared-DB pattern and the DLP chaining approach. What would you do differently?&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>docker</category>
      <category>selfhosted</category>
    </item>
  </channel>
</rss>
