<?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: Daniel J</title>
    <description>The latest articles on DEV Community by Daniel J (@tuxxin).</description>
    <link>https://dev.to/tuxxin</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4055668%2F2923f58e-fe2b-49e8-a07e-3aeb8c4bf8b2.gif</url>
      <title>DEV Community: Daniel J</title>
      <link>https://dev.to/tuxxin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tuxxin"/>
    <language>en</language>
    <item>
      <title>Rebuilding Houston's Courier: New Site, Driver Portal, and a Dispatch System in Progress</title>
      <dc:creator>Daniel J</dc:creator>
      <pubDate>Thu, 03 Sep 2026 15:38:30 +0000</pubDate>
      <link>https://dev.to/tuxxin/rebuilding-houstons-courier-new-site-driver-portal-and-a-dispatch-system-in-progress-18oj</link>
      <guid>https://dev.to/tuxxin/rebuilding-houstons-courier-new-site-driver-portal-and-a-dispatch-system-in-progress-18oj</guid>
      <description>&lt;p&gt;Houston's Courier has been moving freight and time-critical deliveries around the Gulf Coast for decades. Their website had not kept up. This is what we rebuilt, what we surfaced, what we added, and what is still on the bench.&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting with the part customers see
&lt;/h2&gt;

&lt;p&gt;The old site was nearly a decade old. It &lt;em&gt;had&lt;/em&gt; a mobile layout — it just did not work properly, with errors throughout that got worse the smaller the screen got. Underneath that, the site was thin where it counted: very little SEO foundation and effectively no structured data, so search engines had to guess at what the business did, where it operated, and what services it offered.&lt;/p&gt;

&lt;p&gt;The service list had also fallen behind. Not because the company changed direction — Houston's Courier does what it has always done — but because it kept adding capabilities and the website never caught up. Work they were actively selling simply was not on the site.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://houstonscourier.com/" rel="noopener noreferrer"&gt;new site&lt;/a&gt; is a ground-up replacement: same-day delivery leads, the catalog reflects everything the company actually offers in 2026, structured data describes the business properly, and the client login sits on the homepage instead of behind a hostname nobody could remember.&lt;/p&gt;

&lt;h2&gt;
  
  
  One service the site was hiding, and one that is coming
&lt;/h2&gt;

&lt;p&gt;A courier already sends a bonded, uniformed, background-checked person to a customer's door with a package. That position turns out to be worth more than a single delivery.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mobile notary — already offered, never advertised.&lt;/strong&gt; This is not a new service line; Houston's Courier has been doing it. It was nowhere on the old website. Documents that need a notary are frequently the same documents that need a courier, so one visit covers both — and the company was earning none of the search traffic for it, because as far as Google was concerned the service did not exist.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Electronic ID verification for age-restricted deliveries (18+ and 21+) — built, not yet launched.&lt;/strong&gt; Alcohol, tobacco, vape, and certain pharmacy items carry a legal obligation to verify age at handoff. This is a genuinely new capability rather than an unadvertised one, and it ships with the new dispatch system described below — it is not orderable today.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those two are worth separating clearly, because they are different kinds of work. One was a marketing failure with an easy fix — the service existed, the website just never said so. The other required building something that did not exist, and it launches when the new system does.&lt;/p&gt;

&lt;h2&gt;
  
  
  The driver portal, where the compliance actually happens
&lt;/h2&gt;

&lt;p&gt;"We verify ID" is a claim. The driver portal is the evidence. Drivers work from a portal built for a phone in one hand and a package in the other:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Barcode scanning off the air bill.&lt;/strong&gt; The driver scans rather than types. That kills transposed tracking numbers, which are the single most common cause of a package that is physically fine and administratively lost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Photo delivery confirmation.&lt;/strong&gt; A timestamped photo at the drop point, attached to the stop. "It was left at the side door" stops being a memory and becomes a record.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Electronic ID verification at handoff, over a secure network.&lt;/strong&gt; Launching with the new system: the age check is performed and captured electronically at the point of delivery and transmitted over an encrypted connection — not written on a signature sheet, not photographed and emailed, and not reconstructed from memory weeks later when someone asks for proof.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The through-line is that each of these replaces something a driver used to remember with something the system holds, securely. That matters most on the day a client disputes a delivery: the answer is a record retrieved in seconds, rather than a phone call to a driver who has made two hundred stops since.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dispatch: replacing the system, not skinning it
&lt;/h2&gt;

&lt;p&gt;The largest piece of this engagement is roughly two-thirds built, and it is worth being precise about what it replaces.&lt;/p&gt;

&lt;p&gt;Dispatch, driver management, and the customer portal all lived inside one integrated legacy application on &lt;code&gt;manage.houstonscourier.com&lt;/code&gt;. That coupling is the problem. Every change to how dispatchers work risked the customer-facing side, and every change a customer noticed had to be regression-tested against dispatch. Nothing could be improved in isolation.&lt;/p&gt;

&lt;p&gt;The replacement is a standalone system with three separate surfaces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Admin and dispatcher&lt;/strong&gt; — order intake, assignment, and the live board dispatchers work from all day.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Driver&lt;/strong&gt; — the portal above: scanning, photo confirmation, electronic ID capture.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client&lt;/strong&gt; — and this one goes &lt;em&gt;into the new website&lt;/em&gt; rather than beside it. Customers place and track orders on the same domain they landed on, not on a subdomain that looks and behaves like different software, because it was.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Three things ship with it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A suite of new security controls&lt;/strong&gt; across all three surfaces. A system holding delivery addresses, signed proof-of-delivery, and age-verification records is holding sensitive data, and the legacy application was not designed with that in mind.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A far easier experience end to end&lt;/strong&gt; — from submitting an order to paying the invoice. The old flow worked if you already knew it. The new one does not require that.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Continuous route optimization&lt;/strong&gt; using the current Google Maps platform APIs, re-optimizing as the day changes rather than planning once in the morning and hoping. Traffic in Houston does not hold still, and neither should the route.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Splitting one application into three surfaces on a shared core costs more up front than restyling the old one. It buys the ability to change a dispatcher's workflow on a Tuesday without touching anything a customer can see.&lt;/p&gt;

&lt;h2&gt;
  
  
  No AI in the workflow. That is a decision, not an omission.
&lt;/h2&gt;

&lt;p&gt;It is worth stating plainly, because in 2026 the default assumption runs the other way: &lt;strong&gt;no AI touches the day-to-day operation of Houston's Courier.&lt;/strong&gt; Every delivery ticket, every email, every phone call, and every delivery is handled by a real person.&lt;/p&gt;

&lt;p&gt;The software's job here is to remove clerical work and to remember things accurately — scan instead of type, capture instead of recall, re-optimize a route as conditions change. The judgment calls stay with the dispatchers and drivers who know the accounts, the buildings, and which receiving dock actually opens at 7am.&lt;/p&gt;

&lt;p&gt;For a same-day courier that is not nostalgia, it is the product. When a delivery is time-critical and something goes wrong, the customer wants a person who can fix it — not a queue.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the search numbers did
&lt;/h2&gt;

&lt;p&gt;A rebuild is a genuine risk to organic search. New URLs, new structure, and a decade of accumulated signals to carry across — sites lose traffic doing this. Six months on, compared against the six months before:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Impressions: 153K → 273K&lt;/strong&gt;, up 78%&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clicks: 3.05K → 3.84K&lt;/strong&gt;, up 26%&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Worth reading those two together rather than separately. Impressions grew faster than clicks, which means the site now surfaces for a far wider set of queries — including broader, higher-funnel searches that were previously out of reach entirely and that convert at a lower rate by nature. Average click-through moved from about 2.0% to about 1.4% as a result. That is the arithmetic of a site appearing in a great many more places, not a site getting worse at earning the click, and the number that pays the bills — actual visits from search — is up by roughly 790 a month.&lt;/p&gt;

&lt;p&gt;A good share of that is the unglamorous work: real structured data, a service catalog that lists the services, and pages for offerings like mobile notary that were previously invisible to search entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Still to come
&lt;/h2&gt;

&lt;p&gt;The dispatch and portal build is about two-thirds done. The remaining third is the part that has to be right rather than fast: cutting live operations off the legacy system without dropping an order mid-flight, and moving the client portal into the new site so customers stop seeing two different pieces of software.&lt;/p&gt;

&lt;p&gt;Age-restricted delivery goes live at the same time, with its own service page — there is no point advertising a capability before the system that performs it is carrying real traffic.&lt;/p&gt;

&lt;p&gt;We will write that up when it ships, including whatever goes wrong on the way.&lt;/p&gt;




&lt;p&gt;Houston's Courier is a Tuxxin LLC client. If you are running a business on software a decade past its service life — and you can usually tell, because everyone has a workaround for it — &lt;a href="https://tuxxin.com/contact" rel="noopener noreferrer"&gt;get in touch&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>casestudy</category>
      <category>clientwork</category>
      <category>logistics</category>
      <category>dispatch</category>
    </item>
    <item>
      <title>Is curl | bash Safe? What qsa.sh Does Instead</title>
      <dc:creator>Daniel J</dc:creator>
      <pubDate>Thu, 03 Sep 2026 12:52:57 +0000</pubDate>
      <link>https://dev.to/tuxxin/is-curl-bash-safe-what-qsash-does-instead-2in2</link>
      <guid>https://dev.to/tuxxin/is-curl-bash-safe-what-qsash-does-instead-2in2</guid>
      <description>&lt;p&gt;You have seen the pattern in a hundred install docs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://example.com/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is convenient. It is also the single most-argued line in DevOps. Before you paste it into a root shell, it is worth being precise about what it actually does — and about what &lt;code&gt;curl qsa.sh&lt;/code&gt; does &lt;em&gt;not&lt;/em&gt; do, because the two look similar and are not the same thing at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  What &lt;code&gt;curl &amp;lt;url&amp;gt; | bash&lt;/code&gt; actually does
&lt;/h2&gt;

&lt;p&gt;The pipe does exactly what it says. &lt;code&gt;curl&lt;/code&gt; fetches whatever bytes the server sends, and &lt;code&gt;bash&lt;/code&gt; executes them as a shell script — on your machine, with your privileges, right now. There is no preview, no diff, no confirmation step. Whatever the server returns &lt;em&gt;is&lt;/em&gt; the program that runs.&lt;/p&gt;

&lt;p&gt;That is not a hypothetical. It is arbitrary local code execution by design. The risk is not that the pattern is broken; it is that it works perfectly and hands full trust to a remote party. Specifically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;You cannot see what you ran.&lt;/strong&gt; By the time the script executes, you have already run it. Auditing after the fact is not auditing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trust extends to the whole chain.&lt;/strong&gt; You are trusting the domain, its TLS, its DNS, the CDN in front of it, and anyone who can compromise any of those. A server can also detect a piped shell (no TTY) and serve different bytes than it shows in a browser — this has been demonstrated publicly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failure modes get worse.&lt;/strong&gt; A truncated download can leave a half-run script. &lt;code&gt;sudo curl ... | bash&lt;/code&gt; runs remote code as root.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To be fair — and this matters — &lt;code&gt;curl | bash&lt;/code&gt; is not automatically malicious. Downloading a release binary, an &lt;code&gt;apt&lt;/code&gt; package, or a container image is also "run code you didn't read." The pattern's real sins are that it skips the checkpoint where you &lt;em&gt;could&lt;/em&gt; have looked, and that it re-fetches live every time, so a good script today can become a bad script tomorrow with nothing pinned.&lt;/p&gt;

&lt;h2&gt;
  
  
  The safer way to run an install script
&lt;/h2&gt;

&lt;p&gt;If you are going to run one, split fetch from execute so there is a moment to look:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://example.com/install.sh &lt;span class="nt"&gt;-o&lt;/span&gt; install.sh
less install.sh          &lt;span class="c"&gt;# actually read it&lt;/span&gt;
&lt;span class="nb"&gt;sha256sum &lt;/span&gt;install.sh     &lt;span class="c"&gt;# compare to a published checksum, if any&lt;/span&gt;
bash install.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not glamorous. But now there is a checkpoint, and you are running a known artifact instead of a live stream. Prefer signed packages or checksummed binaries when the project offers them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why &lt;code&gt;curl qsa.sh&lt;/code&gt; is a different animal
&lt;/h2&gt;

&lt;p&gt;Here is the part people conflate. &lt;code&gt;curl qsa.sh&lt;/code&gt; &lt;strong&gt;is not&lt;/strong&gt; &lt;code&gt;curl qsa.sh | bash&lt;/code&gt;. There is no pipe into a shell, and there is nothing on our end that expects one.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;curl qsa.sh&lt;/code&gt; makes an HTTP request and &lt;strong&gt;streams text back to your terminal.&lt;/strong&gt; That text is a scan report. Your shell prints it, the same way it would print a README. No script is downloaded to be executed, no code runs on your machine, and adding &lt;code&gt;| bash&lt;/code&gt; would accomplish nothing useful because the output is a human-readable report, not a program.&lt;/p&gt;

&lt;p&gt;The work happens on &lt;strong&gt;our&lt;/strong&gt; side, not yours:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The scan runs from qsa.sh's own real, attributable scanner IP (reverse-DNS &lt;code&gt;scanner.qsa.sh&lt;/code&gt;) — an outside-in view, exactly what an external attacker sees.&lt;/li&gt;
&lt;li&gt;It scans &lt;strong&gt;only the public IP you are connecting from.&lt;/strong&gt; There is no target field; you cannot aim it at anyone else. Your IP is shown with a countdown before anything starts.&lt;/li&gt;
&lt;li&gt;The engine is &lt;a href="https://qsa.sh/how-it-works" rel="noopener noreferrer"&gt;the same open-source tooling you could run yourself&lt;/a&gt;: naabu for port discovery, &lt;code&gt;nmap -sV --script vulners&lt;/code&gt; for service/version and CVE matching, then nuclei for templated checks (&lt;a href="https://qsa.sh/news/engine-update-nmap-7-99-nuclei-3-11-origin-intel" rel="noopener noreferrer"&gt;current engine versions&lt;/a&gt;). No black box.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://qsa.sh/privacy" rel="noopener noreferrer"&gt;Zero retention&lt;/a&gt;: results stream to your terminal and are gone. No stored scan output, no stored IPs, no user-agents, no history.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the trust question inverts. With &lt;code&gt;curl &amp;lt;url&amp;gt; | bash&lt;/code&gt;, the remote server runs code on your machine. With &lt;code&gt;curl qsa.sh&lt;/code&gt;, your machine runs nothing — it just displays what our scanner found looking at your public IP from the outside.&lt;/p&gt;

&lt;h2&gt;
  
  
  Side by side
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;curl &amp;lt;url&amp;gt; | bash&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;curl qsa.sh&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;What comes back&lt;/td&gt;
&lt;td&gt;A shell script&lt;/td&gt;
&lt;td&gt;A text report&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What runs it&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Your shell, on your host&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Nothing — it is printed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Where code executes&lt;/td&gt;
&lt;td&gt;Your machine, your privileges&lt;/td&gt;
&lt;td&gt;Our scanner, server-side&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What it can touch&lt;/td&gt;
&lt;td&gt;Your filesystem, your creds&lt;/td&gt;
&lt;td&gt;Only your public IP, from outside&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retained&lt;/td&gt;
&lt;td&gt;Whatever the script writes&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  A fair caveat, because this is a security site
&lt;/h2&gt;

&lt;p&gt;You should still know who you are talking to. &lt;code&gt;curl qsa.sh&lt;/code&gt; streams text and runs nothing locally — that is true whether you trust us or not, because the output never touches your shell as code. But the &lt;em&gt;report itself&lt;/em&gt; comes from us, so treat qsa.sh like any external scanner: it is a starting point, an attacker's-eye view of your exposed surface, not a full audit.&lt;/p&gt;

&lt;p&gt;One practical note: plain &lt;code&gt;curl qsa.sh&lt;/code&gt; is HTTP. To encrypt the request and response in transit, use &lt;code&gt;curl https://qsa.sh&lt;/code&gt;. Same scan, same report — just protected on the wire. On a network you do not control, prefer the &lt;code&gt;https://&lt;/code&gt; form.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short version
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;curl &amp;lt;url&amp;gt; | bash&lt;/code&gt; is not evil, but it is arbitrary local code execution with no checkpoint — read it, checksum it, or use a signed package first. &lt;code&gt;curl qsa.sh&lt;/code&gt; is not that pattern: it prints a report, runs no local code, and does its scanning from our own IP against only your public IP.&lt;/p&gt;

&lt;p&gt;Run it and read the output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://qsa.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See &lt;a href="https://qsa.sh/how-it-works" rel="noopener noreferrer"&gt;how it works&lt;/a&gt;, what we &lt;a href="https://qsa.sh/privacy" rel="noopener noreferrer"&gt;do and don't retain&lt;/a&gt;, or what the &lt;a href="https://qsa.sh/pricing" rel="noopener noreferrer"&gt;paid tiers&lt;/a&gt; add.&lt;/p&gt;

</description>
      <category>curl</category>
      <category>bash</category>
      <category>shell</category>
      <category>security</category>
    </item>
    <item>
      <title>OAuth Consent Phishing: The Attack a Password Change Does Not Fix</title>
      <dc:creator>Daniel J</dc:creator>
      <pubDate>Thu, 03 Sep 2026 08:07:27 +0000</pubDate>
      <link>https://dev.to/tuxxin/oauth-consent-phishing-the-attack-a-password-change-does-not-fix-1dle</link>
      <guid>https://dev.to/tuxxin/oauth-consent-phishing-the-attack-a-password-change-does-not-fix-1dle</guid>
      <description>&lt;p&gt;The FBI's Internet Crime Complaint Center published &lt;a href="https://www.ic3.gov/PSA/2026/PSA260901" rel="noopener noreferrer"&gt;PSA I-090126&lt;/a&gt; on September 1, 2026, and it describes an attack that quietly defeats the two things most people rely on: changing your password, and having multi-factor authentication turned on.&lt;/p&gt;

&lt;p&gt;Neither one helps here. That is not a flaw in either — it is that this attack never touches your password at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  What consent phishing actually is
&lt;/h2&gt;

&lt;p&gt;You have almost certainly done the legitimate version of this. You sign into some service with “Continue with Google,” a permission screen appears listing what the app wants — read your email, see your files, post on your behalf — and you click &lt;strong&gt;Allow&lt;/strong&gt;. That grant is an OAuth token. It is how a scheduling tool reads your calendar without ever knowing your password.&lt;/p&gt;

&lt;p&gt;Consent phishing is the same flow with a hostile app at the end of it. The attacker registers a real application with a real provider, requests broad permissions, and sends you a link. You land on a genuine login page — the actual Google or Microsoft one, correct domain, valid certificate — and authenticate normally. Then the permission screen appears, and if you approve it, the attacker holds a token that reads your mail and files whenever it likes.&lt;/p&gt;

&lt;p&gt;The IC3 is blunt about the consequence. The access &lt;em&gt;“can only be revoked by the victim invalidating the token in their application security settings; not by changing the password.”&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why your usual response does nothing
&lt;/h2&gt;

&lt;p&gt;Think about what you would do if you suspected an account compromise. Change the password. Check MFA is on. Sign out other sessions, maybe.&lt;/p&gt;

&lt;p&gt;None of that revokes an OAuth grant.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Changing your password&lt;/strong&gt; does not invalidate the token. The token was never derived from your password.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MFA does not stop it.&lt;/strong&gt; You completed MFA yourself, correctly, on the real login page. The attacker never needed to defeat it — you satisfied it and then handed over a key on the next screen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;There is no suspicious login to spot.&lt;/strong&gt; The app is calling an API with a valid token, not signing in from a strange country. Your login history looks clean.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nothing expires on a useful timescale.&lt;/strong&gt; A refresh token can stay valid for months or longer, renewing itself quietly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last point is the one worth sitting with. This is not a break-in you notice and clean up. It is a key you handed out, filed under a permission screen you closed and forgot — genuinely out of sight, out of mind.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who is being targeted
&lt;/h2&gt;

&lt;p&gt;The PSA names &lt;strong&gt;prominent individuals, their family members, and personal acquaintances&lt;/strong&gt;, approached through ordinary commercial messaging apps rather than email. The pretexts impersonate government officials, media figures, and event coordinators, and the ask is mundane: review this document, verify your identity, confirm attendance.&lt;/p&gt;

&lt;p&gt;Family and acquaintances are in that list deliberately. If you are hard to reach directly, the people around you are the way in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Go audit your grants — this is the useful part
&lt;/h2&gt;

&lt;p&gt;Whether or not you have been targeted, this is worth twenty minutes. Most people have not looked at these lists in years, and find things they no longer recognize: a trial from four jobs ago, a plugin that asked for far more than it needed, a “free analyzer” that still reads everything.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Google&lt;/strong&gt; — &lt;a href="https://myaccount.google.com/connections" rel="noopener noreferrer"&gt;myaccount.google.com/connections&lt;/a&gt;. Sort by access level. Anything holding Gmail or Drive read access deserves a hard second look.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Microsoft / Entra&lt;/strong&gt; — &lt;a href="https://myapps.microsoft.com" rel="noopener noreferrer"&gt;myapps.microsoft.com&lt;/a&gt;, then &lt;em&gt;My Account → Privacy → Apps and services&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LinkedIn&lt;/strong&gt; — Settings → Data Privacy → &lt;em&gt;Permitted services&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt; — &lt;a href="https://github.com/settings/applications" rel="noopener noreferrer"&gt;Authorized OAuth Apps&lt;/a&gt;, and check &lt;em&gt;Installed GitHub Apps&lt;/em&gt; separately — they are two different lists and people routinely check only one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dropbox, Slack, Zoom, Meta&lt;/strong&gt; — all keep an equivalent connected-apps page.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Revoke anything you do not actively use. Revocation is instant and free; if you break something you still need, you reauthorize it in a click. That asymmetry is the whole argument for being aggressive here.&lt;/p&gt;

&lt;h2&gt;
  
  
  What good scrutiny looks like
&lt;/h2&gt;

&lt;p&gt;The moment that matters is the permission screen, and it is over in about two seconds. Slow it down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Read the scopes, not the app name.&lt;/strong&gt; The name is chosen by whoever registered the app and can be anything. The permissions are the truth. A PDF viewer does not need to send mail as you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ask why this needs an account at all.&lt;/strong&gt; Reviewing a document rarely requires read/write access to your entire mailbox.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify the sender out of band.&lt;/strong&gt; Not by replying to the message — through a number or address you already had.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treat urgency as the tell.&lt;/strong&gt; A deadline attached to a permission request is doing a job.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  If you think you clicked Allow
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Revoke the grant first&lt;/strong&gt;, on the provider's connected-apps page. Do this before anything else — until the token is gone, the access continues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Then&lt;/strong&gt; change the password and re-check MFA. In that order; the reverse accomplishes nothing on its own.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check mailbox rules and forwarding.&lt;/strong&gt; A common follow-up is a quiet auto-forward or a rule that files security alerts straight into the trash.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review sent mail.&lt;/strong&gt; Access is frequently used to phish your contacts from your real address.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Report it&lt;/strong&gt; — your local FBI field office, or &lt;a href="https://www.ic3.gov" rel="noopener noreferrer"&gt;ic3.gov&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The honest tension
&lt;/h2&gt;

&lt;p&gt;Worth saying plainly: OAuth consent is not the problem. It is a genuine improvement over the thing it replaced, which was typing your actual password into third-party sites and hoping. Every grant that reads your calendar without knowing your password is that design working.&lt;/p&gt;

&lt;p&gt;The weakness is that one screen carries an enormous amount of meaning and gets about two seconds of attention, and that what it hands over is durable in a way people do not expect. A password is something you can change. A consent grant is something you have to &lt;em&gt;remember you gave&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So put it on the calendar. Once or twice a year, open those pages and prune. It takes twenty minutes and it is the only maintenance that actually closes this class of access.&lt;/p&gt;

</description>
      <category>security</category>
      <category>oauth</category>
      <category>phishing</category>
      <category>fbi</category>
    </item>
    <item>
      <title>issued.live is live</title>
      <dc:creator>Daniel J</dc:creator>
      <pubDate>Thu, 03 Sep 2026 08:07:19 +0000</pubDate>
      <link>https://dev.to/tuxxin/issuedlive-is-live-172j</link>
      <guid>https://dev.to/tuxxin/issuedlive-is-live-172j</guid>
      <description>&lt;p&gt;issued.live is open to the public today. This note is about how it is built and why it behaves the way it does, because those choices are the difference between a lookup you can rely on and one that quietly guesses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the corpus stands
&lt;/h2&gt;

&lt;p&gt;At launch the index holds &lt;strong&gt;334 million domains&lt;/strong&gt; and ingested roughly &lt;strong&gt;15.9 million certificates&lt;/strong&gt; in the preceding twenty-four hours, reading 56 of the 58 known Certificate Transparency logs. Ingest sustains tens of thousands of entries per second. Every domain's DNS is re-scanned on a rolling cycle so a record reflects a confirmed observation rather than a lookup performed while you wait.&lt;/p&gt;

&lt;h2&gt;
  
  
  Observational, not authoritative
&lt;/h2&gt;

&lt;p&gt;The most important design decision here is what this service refuses to do.&lt;/p&gt;

&lt;p&gt;We publish what we saw and when we saw it. We do not reconcile that against a registry, we do not fill gaps with plausible values, and we do not derive one field from another because the shapes happen to fit. Where we hold nothing, the field is &lt;code&gt;null&lt;/code&gt; and the interface says so in words. A blank that means "unknown" and a blank that means "does not exist" are different facts, and collapsing them is how a monitoring tool starts lying to the person depending on it.&lt;/p&gt;

&lt;p&gt;This is also why every record carries &lt;code&gt;last_update&lt;/code&gt;. Freshness is yours to judge, not something you have to take on trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  Built to be read by machines first
&lt;/h2&gt;

&lt;p&gt;Most of what queries this service will not be a browser. So the same record is served three ways from one URL: JSON by default, Markdown by appending &lt;code&gt;.md&lt;/code&gt;, and the Model Context Protocol at &lt;code&gt;/mcp&lt;/code&gt; for agents that would otherwise scrape a page built for human eyes. Six MCP tools are exposed, three of which need no credential at all.&lt;/p&gt;

&lt;p&gt;There is a &lt;code&gt;/llms.txt&lt;/code&gt; at the root describing what is worth fetching, and the site root answers plain text to a terminal rather than dumping statistics at it. None of this is decoration — an agent that has to parse layout is an agent that breaks on the next redesign.&lt;/p&gt;

&lt;h2&gt;
  
  
  Free by default
&lt;/h2&gt;

&lt;p&gt;A thousand domain lookups a day require no key, no account, and no sign-up. The rolling certificate feed and the corpus statistics are open on the same terms. A free key exists only for the reverse direction — asking which names sit on an address or a range, and following newly registered domains — because those queries are expensive to answer and worth rate-limiting honestly rather than degrading for everyone.&lt;/p&gt;

&lt;h2&gt;
  
  
  What comes next
&lt;/h2&gt;

&lt;p&gt;Coverage of the remaining CT logs, longer retained history on address changes, and a tighter DNS re-scan interval as capacity allows. If something looks wrong in a record, that is worth reporting — a wrong observation is a bug here, not a rounding error.&lt;/p&gt;

&lt;p&gt;Documentation lives at &lt;a href="https://issued.live/developers" rel="noopener noreferrer"&gt;/developers&lt;/a&gt;. issued.live is built by &lt;a href="https://tuxxin.com" rel="noopener noreferrer"&gt;Tuxxin&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>launch</category>
      <category>certificatetransparency</category>
      <category>dns</category>
      <category>api</category>
    </item>
    <item>
      <title>issued.live: Certificate Transparency, ICANN Registrations and DNS in One API</title>
      <dc:creator>Daniel J</dc:creator>
      <pubDate>Thu, 03 Sep 2026 08:05:57 +0000</pubDate>
      <link>https://dev.to/tuxxin/issuedlive-certificate-transparency-icann-registrations-and-dns-in-one-api-2jdn</link>
      <guid>https://dev.to/tuxxin/issuedlive-certificate-transparency-icann-registrations-and-dns-in-one-api-2jdn</guid>
      <description>&lt;p&gt;Every certificate issued for every domain on the public internet gets written to a public log. Anyone can read them. Almost nobody does — because the raw feed is a firehose of tens of thousands of entries a second, and a certificate on its own doesn’t tell you much.&lt;/p&gt;

&lt;p&gt;That’s the gap &lt;a href="https://issued.live" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;code&gt;issued.live&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; fills. It reads the Certificate Transparency logs continuously, joins them to ICANN zone-file registration data and to its own DNS scans, and keeps the result as one record per domain with a trail of what changed to get there.&lt;/p&gt;

&lt;p&gt;It’s live now, and domain lookups are free with no key and no sign-up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffvuw7fe0xmdfbpyh4ml9.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffvuw7fe0xmdfbpyh4ml9.webp" alt="An issued.live certificate record for tuxxin.com, showing certificate issuer and expiry, certificate ID, current address, network and announced range, first seen in CT, and last updated" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;One record for one domain — certificate, hosting, network, and when each of those was last confirmed.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  One URL, three ways to read it
&lt;/h2&gt;

&lt;p&gt;The thing we care most about here is that the same record is available in whatever shape the thing asking for it actually wants. There are three, and they are the same data underneath.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. JSON, for a script
&lt;/h3&gt;

&lt;p&gt;Point curl at any domain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl issued.live/tuxxin.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "domain": "tuxxin.com",
  "registered": null,
  "expires": null,
  "ssl_expires": "2026-11-28T10:58:19Z",
  "ssl_cert": "431095AFAB96BC5C282ED931FC907068",
  "ssl_issuer": "Google Trust Services",
  "ip": "104.21.65.210",
  "last_update": "2026-08-30T11:16:06Z",
  "first_cert_seen": "2026-08-14T07:47:20Z",
  "tracked": false
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;ssl_cert&lt;/code&gt; value is a stable identifier for the exact certificate, which is more useful than it looks: it lets you tell a genuine reissue from a routine renewal without diffing the whole chain. And &lt;code&gt;last_update&lt;/code&gt; is there so you can judge freshness yourself rather than trusting that the record is current.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Markdown, for a human or a language model
&lt;/h3&gt;

&lt;p&gt;Append &lt;code&gt;.md&lt;/code&gt; to any lookup and you get the same record as a document — certificate, registration, hosting, address history and DNS records, as tables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl issued.live/tuxxin.com.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This exists because a model quoting from a page wrapped in navigation and CSS gets it wrong more often, and burns a pile of tokens doing it. The markdown form is the same data at a fraction of the size. There’s a &lt;code&gt;/llms.txt&lt;/code&gt; at the root that maps what’s worth fetching.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. MCP, for an agent
&lt;/h3&gt;

&lt;p&gt;issued.live speaks the Model Context Protocol directly, so an assistant can query it as a tool rather than scraping pages. Six tools are exposed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;lookup_domain&lt;/code&gt;&lt;/strong&gt; — the full certificate and DNS record for one domain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;recent_certificates&lt;/code&gt;&lt;/strong&gt; — a rolling 30-minute window of certificates as they are logged.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;corpus_stats&lt;/code&gt;&lt;/strong&gt; — how much the corpus holds and how fresh it is.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;domains_on_ip&lt;/code&gt;&lt;/strong&gt; — reverse lookup: which hostnames have been seen on an address. &lt;em&gt;(key required)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;domains_in_range&lt;/code&gt;&lt;/strong&gt; — the same across a small CIDR range. &lt;em&gt;(key required)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;new_domains&lt;/code&gt;&lt;/strong&gt; — newly registered domains from the ICANN zone-file feeds. &lt;em&gt;(key required)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And there is, of course, the website — server-rendered, nothing behind a login, no client-side rendering step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three streams, joined
&lt;/h2&gt;

&lt;p&gt;What makes a record worth reading is that it isn’t one source.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Certificate Transparency logs&lt;/strong&gt; give you certificates as they are issued. &lt;strong&gt;ICANN zone-file feeds&lt;/strong&gt; give you domains as they are registered. &lt;strong&gt;DNS scanning&lt;/strong&gt; gives you where a name actually points — every domain in the corpus is re-scanned for freshness on roughly a 48-hour cycle, merged across four vantage points, so what you get is a confirmed observation rather than a live lookup you have to wait on.&lt;/p&gt;

&lt;p&gt;Joined, those answer questions none of them answer alone: what a domain looks like &lt;em&gt;right now&lt;/em&gt;, what addresses it has rotated through, and what has just appeared that didn’t exist yesterday.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a null means
&lt;/h2&gt;

&lt;p&gt;This is the part we’d point at if you only read one section.&lt;/p&gt;

&lt;p&gt;Registration dates come from zone-file feeds, and they are genuinely absent for a lot of names. So &lt;code&gt;registered: null&lt;/code&gt; means &lt;em&gt;“we do not hold this”&lt;/em&gt; — it never means “this domain is not registered.” The record will not guess, and it will not quietly infer a registration date from a certificate date, because those are not the same thing and treating them as such produces confident nonsense.&lt;/p&gt;

&lt;p&gt;Same discipline on &lt;code&gt;first_cert_seen&lt;/code&gt;: it’s the first time any CT log carried a certificate for that name. An old domain that only recently got its first certificate will show a recent date there. That’s not a bug, it’s what the field means.&lt;/p&gt;

&lt;p&gt;Every page says the same thing in plain language: this is an observation drawn from public logs — what was seen, and when.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feeds and reverse lookups
&lt;/h2&gt;

&lt;p&gt;Two feeds need no key at all. &lt;code&gt;/api/feed&lt;/code&gt; is a rolling 30-minute window of certificates, newest first. &lt;code&gt;/api/stats&lt;/code&gt; is corpus-wide counts — domains known, certificates in the last 24 hours, ingest rate, per-TLD breakdown and log health — served from a snapshot regenerated every ten minutes, so it’s cheap to poll.&lt;/p&gt;

&lt;p&gt;The reverse questions need a key, and it’s free: &lt;code&gt;/api/v1/ip/{ip}&lt;/code&gt; and &lt;code&gt;/api/v1/range/{cidr}&lt;/code&gt; answer which domains resolve to an address or a small range, and &lt;code&gt;/api/v1/nrd&lt;/code&gt; is the newly-registered-domain feed. That’s the half that matters for brand protection — a look-alike domain and its fresh certificate usually go live minutes before the first victim ever clicks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scale
&lt;/h2&gt;

&lt;p&gt;At the time of writing the corpus holds &lt;strong&gt;334,121,692 domains&lt;/strong&gt;, saw &lt;strong&gt;15,892,349 certificates in the preceding 24 hours&lt;/strong&gt;, and is reading 56 of 58 known CT logs. Ingest runs in the tens of thousands of entries per second.&lt;/p&gt;

&lt;p&gt;A thousand lookups a day need no key whatsoever. Beyond that, or for the reverse-IP endpoints, a key is free — just ask.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Pick any domain you own and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl issued.live/yourdomain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the certificate expiry surprises you, that’s the point.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://issued.live" rel="noopener noreferrer"&gt;&lt;strong&gt;issued.live&lt;/strong&gt;&lt;/a&gt; — full API documentation at &lt;a href="https://issued.live/developers" rel="noopener noreferrer"&gt;issued.live/developers&lt;/a&gt;. It joins &lt;a href="https://qsa.sh" rel="noopener noreferrer"&gt;&lt;code&gt;qsa.sh&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://whack.sh" rel="noopener noreferrer"&gt;&lt;code&gt;whack.sh&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://worldip.io" rel="noopener noreferrer"&gt;worldip.io&lt;/a&gt; in the &lt;a href="https://tuxxin.com/projects" rel="noopener noreferrer"&gt;Tuxxin Stack&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>issuedlive</category>
      <category>certificatetransparency</category>
      <category>ssl</category>
      <category>dns</category>
    </item>
    <item>
      <title>curlhub Now Speaks MCP: Correctly Quoted curl for AI Agents</title>
      <dc:creator>Daniel J</dc:creator>
      <pubDate>Thu, 03 Sep 2026 08:05:28 +0000</pubDate>
      <link>https://dev.to/tuxxin/curlhub-now-speaks-mcp-correctly-quoted-curl-for-ai-agents-9j0</link>
      <guid>https://dev.to/tuxxin/curlhub-now-speaks-mcp-correctly-quoted-curl-for-ai-agents-9j0</guid>
      <description>&lt;p&gt;curlhub.sh is now a &lt;strong&gt;Model Context Protocol&lt;/strong&gt; server. If you use Claude Desktop, Cursor, or anything else that speaks MCP, your assistant can call curlhub as a tool instead of guessing at syntax and handing you something that almost works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Point your client at it
&lt;/h2&gt;

&lt;p&gt;One line of config. No key, no signup:&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;"mcpServers"&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;span class="nl"&gt;"curlhub"&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;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://curlhub.sh/mcp"&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;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 endpoint is &lt;code&gt;https://curlhub.sh/mcp&lt;/code&gt; — JSON-RPC 2.0 over HTTP POST, sharing the same keyless quota as the rest of the site: 60 requests a minute per IP.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tool: getting curl quoting right
&lt;/h2&gt;

&lt;p&gt;There is one tool, &lt;code&gt;validate_and_format_curl(url, method?, headers?, data?)&lt;/code&gt;, and it exists because of a specific, boring failure that costs people real time.&lt;/p&gt;

&lt;p&gt;Language models write curl commands constantly, and they get the quoting wrong. Not often — but when they do, it fails &lt;em&gt;silently&lt;/em&gt;. Consider a header value containing an apostrophe:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'X-Note: it'&lt;/span&gt;s fine&lt;span class="s1"&gt;' https://api.example.com
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That apostrophe closes the quoted string. The shell now sees &lt;code&gt;X-Note:&lt;/code&gt;, &lt;code&gt;its&lt;/code&gt;, and &lt;code&gt;fine&lt;/code&gt; as three separate words, and the command either errors confusingly or — worse — runs and does something you did not ask for. Nothing about the text on your screen looks wrong.&lt;/p&gt;

&lt;p&gt;curlhub builds the command by construction instead. Every interpolated value is wrapped in POSIX single quotes, with embedded single quotes rendered as &lt;code&gt;'\''&lt;/code&gt; — close the quoted run, emit an escaped literal quote, reopen. Inside single quotes the shell treats every other byte literally, so &lt;code&gt;$&lt;/code&gt;, backticks, backslashes, semicolons, newlines and globs are all inert. There is exactly one metacharacter to handle, and it is handled. That is the whole trick, and it is why the result is correct rather than usually-correct.&lt;/p&gt;

&lt;p&gt;The same request, formatted properly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'X-Note: it'&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="s1"&gt;'s fine'&lt;/span&gt; &lt;span class="s1"&gt;'https://api.example.com'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Some things should not be escaped into looking fine. These return a 400 with a reason instead of a command:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Non-http(s) schemes.&lt;/strong&gt; curl also speaks &lt;code&gt;file://&lt;/code&gt;, &lt;code&gt;gopher://&lt;/code&gt; and &lt;code&gt;dict://&lt;/code&gt;. A generated command reaching for a local file is a footgun, so we will not write one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Control characters&lt;/strong&gt; in a URL or header name. Quoting makes them shell-inert but not &lt;em&gt;terminal&lt;/em&gt;-inert — an escape sequence can make a pasted line render differently from how it executes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Header names that are not RFC 9110 tokens&lt;/strong&gt;, and non-UTF-8 input.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Bodies use --data-binary, not -d
&lt;/h2&gt;

&lt;p&gt;A detail worth stating because it silently corrupts JSON: &lt;code&gt;-d&lt;/code&gt; strips newlines and carriage returns, and treats a leading &lt;code&gt;@&lt;/code&gt; as a filename. Generated commands use &lt;code&gt;--data-binary&lt;/code&gt;, so your body survives intact.&lt;/p&gt;

&lt;h2&gt;
  
  
  You do not need an agent
&lt;/h2&gt;

&lt;p&gt;The same thing works over plain HTTP, and returns text to curl and JSON to an API client at the same URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://curlhub.sh/format-curl &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Accept: 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;'{"method":"POST","url":"https://api.example.com","data":"{}"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing is fetched and nothing is stored — it is a pure transform, and no outbound connection is ever made. Because of that, private and link-local targets are allowed: building a command for &lt;code&gt;127.0.0.1&lt;/code&gt; or &lt;code&gt;169.254.169.254&lt;/code&gt; is a normal developer task, not a request we need to police.&lt;/p&gt;

&lt;h2&gt;
  
  
  In-browser agents too
&lt;/h2&gt;

&lt;p&gt;Pages here also register the same tool through &lt;code&gt;document.modelContext&lt;/code&gt;, the emerging W3C browser API — native in Edge 147, and in Chrome 149 behind its origin trial. That call is same-origin, so it uses your existing session and quota and no key ever enters the model's context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Discovery
&lt;/h2&gt;

&lt;p&gt;The server advertises itself the standard ways: a &lt;code&gt;Link&lt;/code&gt; header with &lt;code&gt;rel="mcp"&lt;/code&gt; on every response, and a server card at &lt;code&gt;/.well-known/mcp/server-card.json&lt;/code&gt;. Machine-readable documentation for agents lives at &lt;a href="https://curlhub.sh/llms.txt" rel="noopener noreferrer"&gt;/llms.txt&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>aiagents</category>
      <category>modelcontextprotocol</category>
      <category>curl</category>
    </item>
    <item>
      <title>#4 on MalwareBazaar — what that proves, and what it does not</title>
      <dc:creator>Daniel J</dc:creator>
      <pubDate>Thu, 03 Sep 2026 08:04:48 +0000</pubDate>
      <link>https://dev.to/tuxxin/4-on-malwarebazaar-what-that-proves-and-what-it-does-not-j8h</link>
      <guid>https://dev.to/tuxxin/4-on-malwarebazaar-what-that-proves-and-what-it-does-not-j8h</guid>
      <description>&lt;p&gt;whack.sh launched on August 6th. Nearly three weeks in, it is the fourth-largest contributor to abuse.ch MalwareBazaar over the trailing thirty days — listed alongside GovCERT.ch, Switzerland's national computer emergency response team, and researchers with unbroken streaks going back two, three and six years.&lt;/p&gt;

&lt;p&gt;We did not set out to climb a leaderboard. But it is a useful thing to be able to point at, so here is what it does and does not mean.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we have contributed
&lt;/h2&gt;

&lt;p&gt;Every payload our scanners trip is captured, defanged, hashed and given back to the community's threat-intel platforms. Free, no account, no gate — the same feeds every defender already uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;780&lt;/strong&gt; samples to &lt;a href="https://bazaar.abuse.ch/" rel="noopener noreferrer"&gt;MalwareBazaar&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2,975&lt;/strong&gt; indicators to &lt;a href="https://otx.alienvault.com/" rel="noopener noreferrer"&gt;AlienVault OTX&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;673&lt;/strong&gt; samples to &lt;a href="https://www.virustotal.com/" rel="noopener noreferrer"&gt;VirusTotal&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are per-platform counts, not three slices of one number and not a total to be added up — a single sample frequently goes to more than one destination, and OTX counts indicators rather than payloads alone. The live figures, the family breakdown and the SHA-256 list are on our &lt;a href="https://whack.sh/malware-bazaar" rel="noopener noreferrer"&gt;threat-intel contributions page&lt;/a&gt;, which updates every six hours.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is actually in it
&lt;/h2&gt;

&lt;p&gt;Twenty-four distinct families so far, and the shape is worth being honest about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mirai — 418 samples (55%)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Unclassified — 219 (28%)&lt;/li&gt;
&lt;li&gt;CoinMiner — 52&lt;/li&gt;
&lt;li&gt;ConnectWise, Vidar — 13 each&lt;/li&gt;
&lt;li&gt;A long tail: PureLogsStealer, RemusStealer, njrat, AgentTesla, Formbook, AsyncRAT, QuasarRAT, Amadey, MassLogger and a dozen more, down to single samples&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mirai dominating is not a surprise and it is not a boast. Mirai droppers are among the most widely distributed payloads on the internet, and any pipeline pointed at live malicious URLs will surface them in volume. If you want to read that skew as "a lot of one common thing", that is a fair reading.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this proves, and what it does not
&lt;/h2&gt;

&lt;p&gt;The honest claim is narrow, so we will make it precisely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It proves the detection pipeline works on real, current, live malware.&lt;/strong&gt; Not on a curated test corpus, not on samples from a paper. These are payloads that were being served to real visitors at the moment we captured them, on infrastructure that was live, verified independently by three separate platforms that had no reason to take our word for anything. When a scanner tells you a URL is hosting something dangerous, the reasonable question is whether it is right. This is the third-party answer to that question, and anyone can check it — the submissions are public and attributed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It does not prove we are finding things nobody else could.&lt;/strong&gt; A leaderboard measures volume, and volume is the easiest thing to measure. Much of this corpus originates from URLs that were already known to be malicious. Being fourth by count is a statement about throughput and coverage, not about novelty, and we would rather say so than let you infer otherwise.&lt;/p&gt;

&lt;p&gt;The interesting work is the part that does not show up in these numbers yet, and we will write about it when we can show it rather than assert it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why give it away
&lt;/h2&gt;

&lt;p&gt;Every sample we contribute makes the feeds slightly better for everyone, including people who will never pay us anything, including our competitors. That is the correct trade. Threat intelligence that only circulates among paying customers protects the people who can afford it and leaves everyone else carrying the same risk with less warning. The economics of malware distribution already favor the attacker; hoarding indicators widens that gap.&lt;/p&gt;

&lt;p&gt;abuse.ch in particular runs a set of platforms that a very large part of the defensive internet quietly depends on, largely without funding and largely without credit. Contributing to MalwareBazaar is the cheapest possible way for us to be a net positive to that, and it costs us nothing we would not have spent anyway.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is next
&lt;/h2&gt;

&lt;p&gt;There is a structural gap in the public corpora that we keep running into: payloads gated behind traffic distribution systems are systematically underrepresented, because the thing that makes a TDS a TDS is that it does not serve to whoever asks. A scanner that looks like a datacenter gets a harmless page. Someone on a residential connection with the right referrer gets the payload.&lt;/p&gt;

&lt;p&gt;We are building toward measuring that properly. When we have something demonstrable we will publish the measurements, not the conclusions.&lt;/p&gt;

&lt;p&gt;In the meantime, the contribution page is live and public: &lt;a href="https://whack.sh/malware-bazaar" rel="noopener noreferrer"&gt;whack.sh/malware-bazaar&lt;/a&gt;. If you are a researcher and want the SHA-256 list or the JSON, both are one click from that page, and you do not need an account.&lt;/p&gt;

</description>
      <category>threatintelligence</category>
      <category>malwarebazaar</category>
      <category>abusech</category>
      <category>otx</category>
    </item>
    <item>
      <title>Webshot Now Speaks MCP: Screenshots as a Tool for AI Agents</title>
      <dc:creator>Daniel J</dc:creator>
      <pubDate>Thu, 03 Sep 2026 08:04:27 +0000</pubDate>
      <link>https://dev.to/tuxxin/webshot-now-speaks-mcp-screenshots-as-a-tool-for-ai-agents-5epk</link>
      <guid>https://dev.to/tuxxin/webshot-now-speaks-mcp-screenshots-as-a-tool-for-ai-agents-5epk</guid>
      <description>&lt;p&gt;Webshot.site now speaks the &lt;strong&gt;Model Context Protocol&lt;/strong&gt;. If you use Claude Desktop, Cursor, or anything else that talks MCP, your assistant can render a page and look at it directly — no copy-pasting URLs, no describing what you see.&lt;/p&gt;

&lt;h2&gt;
  
  
  Point your client at it
&lt;/h2&gt;

&lt;p&gt;One line of config, no key, no signup:&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;"mcpServers"&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;span class="nl"&gt;"webshot"&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;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://webshot.site/mcp"&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;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 endpoint is &lt;code&gt;https://webshot.site/mcp&lt;/code&gt;, JSON-RPC 2.0 over HTTP POST. It exposes a single tool:&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="nf"&gt;capture_sandbox_webshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;viewport&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt; &lt;span class="nx"&gt;full_page&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt; &lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ask your assistant to "take a screenshot of example.com and tell me what's above the fold" and it will call that tool, get back an image, and answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it returns a link, not the image
&lt;/h2&gt;

&lt;p&gt;The obvious implementation is to base64 the PNG and hand it straight to the model. We deliberately don't. A modest screenshot is 25–200 KB, which becomes a wall of base64 in the model's context window and crowds out the actual conversation. Most agents can't do anything useful with those bytes anyway.&lt;/p&gt;

&lt;p&gt;So the tool returns a short JSON envelope with a link:&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;"ok"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"image_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://webshot.site/shot/&amp;lt;token&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"format"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"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;"mode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"desktop_viewport"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bytes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;26600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"credits"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&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 link is public, session-free and reusable — you can hand it to another tool, drop it in a ticket, or open it yourself. The token is 128 bits of randomness, so it is unguessable, and it is the only thing that authorises access.&lt;/p&gt;

&lt;h2&gt;
  
  
  You don't need an agent to use this
&lt;/h2&gt;

&lt;p&gt;The same JSON envelope is available over plain HTTP. Add &lt;code&gt;&amp;amp;response=json&lt;/code&gt; to a normal capture request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s1"&gt;'https://webshot.site/api/capture?url=https://example.com&amp;amp;response=json'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without that parameter the response is still the raw image, byte for byte as before. Nothing about the existing API changed — this is strictly additive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Credits, not captures
&lt;/h2&gt;

&lt;p&gt;Worth being precise, because this is the thing people plan around wrongly. The keyless allowance is &lt;strong&gt;5 credits per 15 minutes per IP&lt;/strong&gt;, and credits are not captures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A viewport capture costs &lt;strong&gt;1 credit&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;A full-page or custom-size capture costs &lt;strong&gt;2&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The default &lt;code&gt;mode&lt;/code&gt; is &lt;code&gt;desktop_full&lt;/code&gt;, which is full-page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So a default anonymous call spends 2 credits, and you get two of them per window rather than five. Pass &lt;code&gt;full_page=false&lt;/code&gt; (or &lt;code&gt;mode=desktop_viewport&lt;/code&gt; over HTTP) to spend 1 and get five. Output format does not affect cost. Your live bucket is always readable at &lt;code&gt;GET /throttle-status&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you need more, &lt;a href="https://webshot.site/pricing" rel="noopener noreferrer"&gt;API plans&lt;/a&gt; start at $1.99/month and keys are issued immediately at checkout.&lt;/p&gt;

&lt;h2&gt;
  
  
  One caveat: it is slow, and that is fine
&lt;/h2&gt;

&lt;p&gt;A capture is a real headless-Chrome render — it loads the page, waits for it to settle, and photographs it. That takes &lt;strong&gt;10–60 seconds&lt;/strong&gt;. Set your MCP client timeout to 90 seconds or more, or you will see spurious failures on perfectly good captures.&lt;/p&gt;

&lt;h2&gt;
  
  
  In-browser agents too
&lt;/h2&gt;

&lt;p&gt;Pages on this site also register the same tool through &lt;code&gt;document.modelContext&lt;/code&gt;, the emerging W3C browser API for exposing page capabilities to AI. That works natively in Edge 147 and in Chrome 149 behind its origin trial. Because the call is same-origin it uses your existing session and quota, which means &lt;strong&gt;no API key ever enters the model's context&lt;/strong&gt; — a property worth having if you are handing tools to something that might quote them back at you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Safety
&lt;/h2&gt;

&lt;p&gt;The capture runs in an isolated sandbox, and private, loopback and cloud-metadata addresses are refused. Pointing it at a suspicious URL is the intended use: you get to see what a page looks like without your own browser going there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Docs
&lt;/h2&gt;

&lt;p&gt;Machine-readable documentation for agents lives at &lt;a href="https://webshot.site/llms.txt" rel="noopener noreferrer"&gt;/llms.txt&lt;/a&gt;, and the full human reference — including the MCP section — is on the &lt;a href="https://webshot.site/developers" rel="noopener noreferrer"&gt;developers page&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>aiagents</category>
      <category>modelcontextprotocol</category>
      <category>api</category>
    </item>
    <item>
      <title>iNetPanel 1.26: Debian 13 (Trixie) Support and an HTTPS Setup Wizard</title>
      <dc:creator>Daniel J</dc:creator>
      <pubDate>Thu, 03 Sep 2026 08:04:06 +0000</pubDate>
      <link>https://dev.to/tuxxin/inetpanel-126-debian-13-trixie-support-and-an-https-setup-wizard-25o3</link>
      <guid>https://dev.to/tuxxin/inetpanel-126-debian-13-trixie-support-and-an-https-setup-wizard-25o3</guid>
      <description>&lt;p&gt;&lt;strong&gt;iNetPanel 1.26.0&lt;/strong&gt; is out. It adds support for &lt;strong&gt;Debian 13 (Trixie)&lt;/strong&gt; and serves the setup wizard over HTTPS. If you are running Debian 12, nothing changes and there is nothing you need to do.&lt;/p&gt;

&lt;p&gt;Most of this release is the unglamorous work of making a clean install actually finish on a new Debian release. The interesting part is &lt;em&gt;what&lt;/em&gt; broke, because almost none of it is specific to iNetPanel — if you self-host on Trixie you will hit several of these regardless of what panel you use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Both Debian 12 and Debian 13 are supported
&lt;/h2&gt;

&lt;p&gt;Debian 12 (Bookworm) left regular support on 11 July 2026 but stays on LTS until &lt;strong&gt;June 2028&lt;/strong&gt;. There is no need to migrate an existing server. Debian 13 (Trixie) is now a first-class target, verified by a full clean install: install, create an account, issue DNS and a certificate, then delete the account.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually broke on Trixie
&lt;/h2&gt;

&lt;h3&gt;
  
  
  dnsutils no longer exists
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;dnsutils&lt;/code&gt; was a transitional package and Trixie dropped it. This was the first hard failure — the installer died before installing anything at all. The installer now uses &lt;code&gt;bind9-dnsutils&lt;/code&gt;, which exists on both releases.&lt;/p&gt;

&lt;h3&gt;
  
  
  The PHP repository was pinned to bookworm
&lt;/h3&gt;

&lt;p&gt;This one failed later and far more confusingly. The &lt;code&gt;bookworm&lt;/code&gt; suite still resolves on Trixie, so the repository added cleanly and the error surfaced much further into the install: sury's bookworm build depends on &lt;code&gt;libssl3&lt;/code&gt;, and Trixie ships &lt;code&gt;libssl3t64&lt;/code&gt; instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  cloudflared deliberately stays on bookworm
&lt;/h3&gt;

&lt;p&gt;Cloudflare publishes no Trixie suite. The bookworm package is a static Go binary with no dependencies, so it runs correctly on Trixie and pinning it there is the right call rather than a workaround. There is now also a direct &lt;code&gt;.deb&lt;/code&gt; fallback, so a repository outage cannot abort an install part-way through.&lt;/p&gt;

&lt;h3&gt;
  
  
  PHP pinning is now built dynamically
&lt;/h3&gt;

&lt;p&gt;phpMyAdmin depends on &lt;code&gt;php-cli&lt;/code&gt; and &lt;code&gt;php-mysql&lt;/code&gt;, which on Trixie resolve to a complete PHP 8.4 stack. The old pin only blocked 8.6 and above, so you could finish an install with two full PHP stacks side by side. The pin is now generated from the PHP version actually in use.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup wizard now uses HTTPS
&lt;/h2&gt;

&lt;p&gt;The wizard collects your admin password and, a few steps later, your Cloudflare API key. Both previously travelled over plain HTTP. There was an HTTPS option, but it required running &lt;code&gt;panel_ssl.sh&lt;/code&gt; by hand — which happens &lt;em&gt;after&lt;/em&gt; those credentials have already been sent.&lt;/p&gt;

&lt;p&gt;The installer now generates a self-signed certificate, serves the panel over TLS on port 443, and redirects HTTP. Your browser will warn you once; that is expected for a self-signed certificate and the closing message explains it. Replace it with a trusted certificate whenever you like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;inetp panel_ssl &amp;lt;hostname&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Fixes worth knowing about
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Certificates could silently be self-signed on Debian 13
&lt;/h3&gt;

&lt;p&gt;The worst kind of bug: it reported success. Trixie ships certbot 4.0, and &lt;code&gt;certbot-dns-cloudflare&lt;/code&gt; 4.x removed support for the Cloudflare Global API Key. Issuance would fail, the panel would quietly fall back to a self-signed certificate, and then report the domain as done.&lt;/p&gt;

&lt;p&gt;It now uses a scoped API token (&lt;strong&gt;Settings → Cloudflare&lt;/strong&gt;), refuses rather than degrading, and verifies the certificate issuer before calling a domain complete.&lt;/p&gt;

&lt;h3&gt;
  
  
  inetp db_repair did nothing
&lt;/h3&gt;

&lt;p&gt;MariaDB 11.x ships most &lt;code&gt;mysql*&lt;/code&gt; compatibility symlinks but not &lt;code&gt;mysqlcheck&lt;/code&gt;. The error was discarded, so the command reported zero tables checked and exited successfully.&lt;/p&gt;

&lt;h3&gt;
  
  
  Changing the SSH port could lock you out
&lt;/h3&gt;

&lt;p&gt;Under systemd socket activation the listening port comes from &lt;code&gt;ssh.socket&lt;/code&gt;, not &lt;code&gt;sshd_config&lt;/code&gt; — but the safety check used &lt;code&gt;sshd -T&lt;/code&gt;, which reads the config file. It now verifies the actual listener and keeps the socket unit in step.&lt;/p&gt;

&lt;h3&gt;
  
  
  WireGuard failed where iptables was absent
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;iptables&lt;/code&gt; is not a dependency of &lt;code&gt;wireguard-tools&lt;/code&gt;, and firewalld 2.x no longer pulls it in. The NAT rules now prefer &lt;code&gt;nft&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  A newly added domain could return 503
&lt;/h3&gt;

&lt;p&gt;An API request that omitted the PHP version reloaded a PHP-FPM service that did not exist, so the new pool's socket was never created. A related case: a domain set to inherit the panel default produced an invalid service name, and its FPM reload silently never happened.&lt;/p&gt;

&lt;h2&gt;
  
  
  Also in this release
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;install_LAMP.sh&lt;/code&gt; is now tracked in the repository, so it is covered by the same linting and secret scanning as every other script.&lt;/p&gt;

&lt;h2&gt;
  
  
  Upgrading
&lt;/h2&gt;

&lt;p&gt;Existing Debian 12 servers are unaffected and need no action. To move an existing install onto HTTPS, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;inetp panel_ssl &amp;lt;hostname&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;iNetPanel is free and GPL-3.0. Full release notes and downloads are on &lt;a href="https://github.com/tuxxin/iNetPanel/releases/tag/v1.26.0" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>inetpanel</category>
      <category>debian13</category>
      <category>trixie</category>
      <category>release</category>
    </item>
    <item>
      <title>The FBI QTFY Advisory: When Attackers Rent the Same Proxies You Do</title>
      <dc:creator>Daniel J</dc:creator>
      <pubDate>Thu, 27 Aug 2026 19:38:02 +0000</pubDate>
      <link>https://dev.to/tuxxin/the-fbi-qtfy-advisory-when-attackers-rent-the-same-proxies-you-do-icg</link>
      <guid>https://dev.to/tuxxin/the-fbi-qtfy-advisory-when-attackers-rent-the-same-proxies-you-do-icg</guid>
      <description>&lt;p&gt;On August 26th the FBI, NSA and US Cyber National Mission Force published joint advisory JCSA-20260826-01 on a China-linked group tracked as QTFY. It is marked TLP:CLEAR and is freely available in full. Everything attributed below is the advisory's finding, not ours — we are reporting on a public government document, and we did not independently verify its attribution.&lt;/p&gt;

&lt;p&gt;We are writing about it because one detail in it speaks directly to how URL scanning works, and because we checked our own data against it and found nothing. Both halves are worth saying.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://whack.sh/news/fbi-qtfy-advisory-shared-proxy-infrastructure" rel="noopener noreferrer"&gt;-Read more&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>threathunting</category>
      <category>ioc</category>
      <category>osint</category>
    </item>
    <item>
      <title>curlhub.sh Curl Based CLI Dev Tools</title>
      <dc:creator>Daniel J</dc:creator>
      <pubDate>Fri, 31 Jul 2026 18:40:00 +0000</pubDate>
      <link>https://dev.to/tuxxin/curlhubsh-curl-based-cli-dev-tools-16nj</link>
      <guid>https://dev.to/tuxxin/curlhubsh-curl-based-cli-dev-tools-16nj</guid>
      <description>&lt;p&gt;A suite of developer tools you run with the curl you already have: UUIDs, hashes, JSON End-points, JWTs, JSON, QR, File Transfers and more. Nothing to install, and no signup required. "curl curlhub.sh" to see list of commands or visit &lt;a href="https://curlhub.sh" rel="noopener noreferrer"&gt;https://curlhub.sh&lt;/a&gt; to view all tools full details and soon contribute.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;root@web01:~#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;curl curlhub.sh
&lt;span class="go"&gt;curlhub.sh  —  CLI-first developer utilities
Zero-setup tools you curl straight from the terminal.

Generators
  /uuid      RFC 4122 v4 UUID.
&lt;/span&gt;&lt;span class="gp"&gt;  /pass      High-entropy password / API key / token. CLI: server-side CSPRNG over TLS;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;web: client-side. Never logged. &lt;span class="o"&gt;(&lt;/span&gt;https&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;
Utilities
&lt;/span&gt;&lt;span class="gp"&gt;  /qr        ANSI/UTF-8 QR code from ?data. Nothing stored server-side;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;use HTTPS or pipe stdin &lt;span class="k"&gt;for &lt;/span&gt;sensitive payloads &lt;span class="o"&gt;(&lt;/span&gt;a ?data&lt;span class="o"&gt;=&lt;/span&gt; value appears &lt;span class="k"&gt;in &lt;/span&gt;request URLs&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="go"&gt;
Encoding
  /b64       Base64 encode / decode. (https)
  /hash      MD5 / SHA-1 / SHA-256 / SHA-512 of input. (https)

Developer
  /json      Validate + prettify + colorize JSON. (https)
&lt;/span&gt;&lt;span class="gp"&gt;  /jwt       Decode &amp;amp; pretty-print JWT header/payload. No verify;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;token never logged. &lt;span class="o"&gt;(&lt;/span&gt;https&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;  /status    Explain an HTTP status code + troubleshooting.
  /cron      Translate a cron expression to English + next run times.
  /ua        Parse the User-Agent you sent (browser / OS / engine / device).
  /headers   Echo the request headers you sent (+ the edge view). Your own request, not a remote audit.
  /hook      Webhook inspector: mint a temp endpoint, inspect incoming HTTP. (https)

Text &amp;amp; Logs
  /md        Render Markdown to colorized ANSI (safe, bounded parser). (https)
  /p         Pastebin: pipe text/logs to a short URL (plaintext in terminal, highlighted on web). (https)

Network
  /cidr      Subnet / CIDR math: range, netmask, broadcast, host count.
  /ip        Your public IP (thin). Geo/ASN live at worldip.io.
&lt;/span&gt;&lt;span class="gp"&gt;  /whois     Domain registration / registrar / dates (public OSINT;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;rate-limited + cached&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="go"&gt;
Security
  /ssl       Decode a PEM certificate or CSR you paste (expiry, issuer, SANs, key). No outbound connection. (https)

File Transfer
&lt;/span&gt;&lt;span class="gp"&gt;  /u         Ephemeral file drop (&amp;lt;=100 MB). ANSI QR;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;auto-purge after 1 download or TTL. &lt;span class="o"&gt;(&lt;/span&gt;https&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;
Docs
  /man       Community CLI cheat-sheet wiki (read-only over CLI).

Family
  /port      Port scan of your own IP → hands off to qsa.sh.
  /scan      Vulnerability / threat scan of your IP → hands off to qsa.sh.
  /urlscan   Multi-egress URL scan → hands off to whack.sh.

&lt;/span&gt;&lt;span class="gp"&gt;Details: curl curlhub.sh/help/&amp;lt;tool&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;·   Spec: curl curlhub.sh/spec
&lt;span class="go"&gt;Family:  qsa.sh (audit your IP) · whack.sh (scan a URL) · worldip.io (IP intel)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please feel free to leave a comment with feedback, feature requests, etc. &lt;/p&gt;

</description>
      <category>cli</category>
      <category>tooling</category>
      <category>api</category>
      <category>developer</category>
    </item>
    <item>
      <title>Whack.sh - Multi-egress URL Threat Scanner</title>
      <dc:creator>Daniel J</dc:creator>
      <pubDate>Fri, 31 Jul 2026 17:50:09 +0000</pubDate>
      <link>https://dev.to/tuxxin/whacksh-multi-egress-url-threat-scanner-8fi</link>
      <guid>https://dev.to/tuxxin/whacksh-multi-egress-url-threat-scanner-8fi</guid>
      <description>&lt;p&gt;Traffic Direction Systems (TDS) have become a massive headache for analysts. By fingerprinting IPs, attackers can dynamically route traffic—hiding malicious payloads from security tools while successfully targeting residential, mobile, or specific ASNs.&lt;/p&gt;

&lt;p&gt;The problem? Almost every URL scanner out there uses datacenter-based egress IPs. Attackers know this, so they block or cloak against datacenter ranges.&lt;/p&gt;

&lt;p&gt;I ran into this wall while investigating malware distributed via a lapsed corporate domain. The standard scanners were returning clean results or blocked pages, but my home connection was still being served malware. Doing the analysis manually was a massive bottleneck, so I built a solution: whack.sh.&lt;/p&gt;

&lt;p&gt;What it does: Whack allows you to scan any URL simultaneously through multiple egress options: Datacenter, Residential, Mobile, VPN, and even BYO IP. It then diffs the captures (HAR files) to expose the cloaking, TDS routing, phishing, and malware that traditional datacenter-only scanners miss.&lt;br&gt;
The Origin &amp;amp; Investigation: I’ve been working on this for over a month and have already run over 150,000 scans of known threat URLs. The early MVP was basic but proved the concept: diffing HAR files of the exact same URL across different categorized ASNs immediately exposed the evasion tactics.&lt;/p&gt;

&lt;p&gt;I actually reported my initial findings on this specific threat to the FBI IC3 on Monday, June 15th. Three days later, IC3 pushed out a PSA specifically regarding TDS. (I’ll be publishing a few in-depth articles on my company's site detailing these findings in the coming weeks).&lt;/p&gt;

&lt;p&gt;Under the Hood (TDS-over-TDS): One of the most interesting things the tool exposed during this process is that TDS isn't just happening at the redirect layer. I found several instances of TDS-over-TDS (redirect layer + payload delivery layer). Malicious actors are using real-time API calls or compressed local IP intelligence to serve entirely different payloads based on the exact environment (e.g., Windows vs. Mobile/Android/Chrome vs. Mobile/iOS/Safari).&lt;/p&gt;

&lt;p&gt;Community Integration: I want this data to be useful to the broader community, so any threats found by whack.sh are automatically published to Abuse.ch: &lt;a href="https://bazaar.abuse.ch/user/42023/" rel="noopener noreferrer"&gt;https://bazaar.abuse.ch/user/42023/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’m putting the final polish on the site and planning to officially launch on or before August 4th. In the meantime, I would love to hear your thoughts on the concept! What features would you want to see, or what specific evasion tactics would you want to test against it when it goes live?&lt;/p&gt;

</description>
      <category>security</category>
      <category>virus</category>
      <category>api</category>
      <category>tooling</category>
    </item>
  </channel>
</rss>
