Showing posts with label patch. Show all posts
Showing posts with label patch. Show all posts

Google OSS VRP Pause What It Means for STA Research

Sunday, October 04, 2026

Google's OSS VRP Pause: What It Means for STA Research and the Disclosure Ecosystem

On 1 October 2026, Google announced that it would stop accepting product vulnerability submissions to its Open Source Software Vulnerability Reward Program (OSS VRP). The reason: an overwhelming influx of AI-generated reports, including hallucinations, non-reproducible findings, and automated submissions that consumed engineering time without adding security value. The pause took effect the same day and is expected to last until at least Q1 2027.

This is not an isolated incident. Intel had already suspended its bug bounty program. Linux maintainers reported being flooded with AI-generated CVE reports, with some projects dropping support for older drivers as a direct consequence. The bug bounty ecosystem is buckling under the weight of automated noise.

But this post is not about those programs. It is about what the pause means for a specific, ongoing investigation, STA Research, and for the broader problem of how legitimate security findings survive in an environment saturated with AI-generated noise.


1. What exactly was suspended

Three distinctions matter:

Program Status Scope
OSS VRP: product vulnerabilities Suspended as of 1 Oct 2026 Code flaws, logic errors, design defects in Google's public repositories
OSS VRP: supply chain reports Active Dependencies, build pipelines, third-party components
Android VRP Active Android platform, Pixel firmware, Titan M security chip
Chrome VRP Active Chrome browser, Chromium
Cloud VRP Active Google Cloud products
Patch Rewards Program Active Proactive security improvements in open source

The suspension does not affect reports submitted before 1 October 2026, and it does not affect the Android VRP or Chrome VRP programs. Google has explicitly encouraged researchers to use Cloud VRP and Patch Rewards as alternative channels.


2. The case that matters: A-477279924

STA Research has an open case in the Google Android VRP: A-477279924, submitted on 20 January 2026. The case documents a class of defects in AOSP's handling of structured text across Binder boundaries, including unbounded TaskInfo serialization, missing size gates in Task.fillTaskInfo(), and the cascade of failures that follows when a single oversized task state is materialized repeatedly across multiple framework interfaces.

The case is currently blocked on an internal dependency (477593694), which according to my analysis corresponds to AOSP CL 3989977, a fix that exists internally at Google but has not been made public.

A-477279924 is not in the suspended program. It lives in Android VRP, not OSS VRP. But the pause matters because:

  1. Shared triage resources. The engineers and maintainers who process Android VRP reports are part of the same security organization that has been overwhelmed by OSS VRP submissions. The burnout described in Google's announcement is not confined to one program.
  2. Guilt by association. A 40-page technical report with multiple vectors, complete stack traces, and AOSP source verification is exactly the kind of submission that a triage engineer, saturated by AI-generated noise, might mistake for automation. The risk is not that the work is invalid. The risk is that the signal is lost in the noise.
  3. The fix is already internal. The fact that AOSP CL 3989977 exists means Google has already identified the defect. The question is whether the OSS VRP pause delays its public release, or whether it accelerates internal prioritization to close the loop without public disclosure.

3. Why this affects every legitimate researcher

The OSS VRP pause is a symptom of a larger problem: the cost of generating a report has collapsed, but the cost of validating one has not.

Before large language models, writing a vulnerability report required understanding the code, reproducing the behavior, and articulating the impact. The effort served as a natural filter. Today, a model can produce a 3,000-word report with plausible-sounding analysis and fabricated stack traces in seconds. The human reviewer still has to read it, verify it, and reject it, consuming the same time whether the report is real or hallucinated.

Google's response (pause the program, redesign the intake process, return in Q1 2027) is rational from a resource-management perspective. But it creates a perverse incentive: the noise wins by silencing the signal. Legitimate researchers whose reports are already in the queue, or who discover new vulnerabilities during the pause, have no clear path to disclosure through the affected program.

The alternatives Google suggests (Cloud VRP, Patch Rewards) are valid, but they do not cover the same scope. A finding in AOSP's frameworks/base that affects Android devices is not automatically a Cloud VRP issue. The Patch Rewards Program rewards proactive fixes, not vulnerability reports. The gap is real.


4. What this means for STA Research

STA has always been a long-term investigation. The initial report was submitted in January 2026. The finding has been extended through 8 reproduction sessions, 31 documented crash instances, and verification against AOSP source code. The work predates the OSS VRP pause by months.

Three practical consequences:

1. The Android VRP case remains active, but patience is required.
A-477279924 is not suspended. The internal dependency (477593694) is the bottleneck, not the program status. Follow-up should continue, but expectations should be calibrated to the broader organizational pressure.

2. Public documentation becomes more important, not less.
When official channels are congested, the blog and the GitHub repository become the primary record. The technical report is published. The PoC is published. The evidence is timestamped. The absence of a public patch does not mean the finding is invalid. It means the system is slow.

3. Alternative disclosure channels matter.
The CVE assignment process through INCIBE to MITRE is independent of Google's VRP infrastructure. The HackerOne dispute for Xiaomi (#4064049) follows a different path. These are not substitutes for Android VRP, but they are parallel tracks that do not depend on the paused program.


5. The bigger question: how does disclosure survive AI noise?

The OSS VRP pause is not the end of bug bounties. It is an inflection point. The industry is being forced to redesign intake, triage, and validation processes around a new reality: automated report generation is cheap, and human review is not.

Some possible directions:

  • Proof-of-work for reports. Require a reproducible PoC, a signed environment fingerprint, or a hash-verified test case before a report enters the queue.
  • Tiered intake. Separate "first-pass automated scan" reports from "human-verified, reproducible" reports, with different processing paths.
  • Reputation systems. Weight reports by the researcher's history of valid findings, with new submitters routed through stricter validation.
  • AI-assisted triage. Use models to pre-filter obvious hallucinations, but with the understanding that this creates new failure modes.

None of these are perfect. All of them shift the burden somewhere. But the current model, where a single invalid report costs the same to process as a valid one, is not sustainable.


6. What this means for an independent researcher

There is a version of this article that would end at section 5, with the systemic analysis complete and the policy recommendations neatly laid out. That version would be accurate. It would also be incomplete, because it would leave out the part that matters most to those of us who do this work without institutional backing.

The asymmetry was already there before AI. Researchers working at large security firms have salaries, legal teams, PR departments, and colleagues who can validate a finding before it goes out. An independent researcher has a laptop, a test device, and a blog. When a report is ignored, misclassified, or closed without explanation, the institutional researcher moves on to the next thing on their employer's roadmap. The independent researcher carries the cost personally: the hours spent, the reputational risk of publishing, the ambiguity of not knowing whether the work will ever be acknowledged.

AI noise did not create this asymmetry. It made it worse.

The verification burden falls hardest on those with the least capacity to bear it. When triage teams are overwhelmed, the natural response is to apply stricter filters. That is rational. But stricter filters favor submissions that come with institutional credibility markers: company letterheads, internal references, coordinated timelines. A careful independent report, correctly evidenced but unadorned, is more likely to be filtered out than a mediocre report from a known entity. The playing field tilts further, not less.

And then there is the money. Or rather, the absence of it. Bug bounty payouts are inconsistent, but they exist. CVE assignment does not pay anything. Blog readers do not fund research. This work is not a job. There is no salary, no retainer, no consulting fee waiting at the end of a successful reproduction. When the STA investigation was submitted to Google in January 2026, the acknowledgment came with a partial payment of $250. That amount does not begin to cover the hours invested: 8 reproduction sessions across 4 weeks, 31 documented crash instances, 8 bugreports collected by hand, hundreds of logcat lines read one at a time, AOSP source verified commit by commit against android.googlesource.com. If this were billed at any professional rate, the invoice would be five figures. It was not billed. It was never going to be.

This is not a complaint about a specific payout being too low. It is a description of how the economics actually work. The bug bounty programs exist to incentivize disclosure, and for some researchers at some companies, they do. But for the independent researcher working on a class of defects that do not fit neatly into a single CVE, the payout, when it comes, is a symbolic acknowledgment, not compensation. The reward is the recognition. If the recognition does not come, nothing does.

Reputation becomes the only currency, and it is hard to build from scratch. For someone with prior credits from Microsoft, Google, and Mozilla, a closed case is a setback but not a career risk. For someone starting today, without those credits, a single misclassification can be the end of the attempt. The OSS VRP pause raises the barrier to entry not by making the work harder, but by making the acknowledgment of the work less likely. That is a cost the industry is paying without fully pricing it in.

Public documentation is the only defense that does not depend on anyone's goodwill. This is why I keep writing the blog. This is why the GitHub repository exists. This is why every bugreport, every stack trace, every timestamp, every hash is preserved in the open. Not because publication is a threat to anyone, but because publication is the only record that survives a program's silence. When Google pauses OSS VRP, when Xiaomi closes a case as "not applicable" while confirming an internal ticket, when MITRE takes months to assign a CVE, the blog is what remains. It is not a substitute for official acknowledgment, but it is not dependent on it either.

What sustains independent research is not the payout. It is the craft. It is the satisfaction of finding something real, of documenting it correctly, of leaving a trail that another researcher can follow. It is the conversations with people who understand why a 124-byte transaction failing in the same binder session as a 1.1 MB transaction is interesting, when almost no one else does. It is the small community of researchers who recognize each other's work not because a program validated it, but because the work itself stands on its own.

I am not writing this to complain. I am writing it because the current conversation about AI noise in bug bounties is happening mostly among people whose institutional positions protect them from the consequences. The companies will adapt. The programs will redesign. The platforms will survive. The question that is not being asked loudly enough is: what happens to the researchers who cannot wait for the redesign?

Some will move on to other work. Some will publish less. Some will stop. The loss will not be visible in any quarterly report, because the value of a finding that was never made is not measurable. But it is real, and it is being priced into the ecosystem silently.

For my part, I intend to keep going. STA has too much unfinished business: the CVE assignment through INCIBE and MITRE, the HackerOne dispute with Xiaomi, the follow-up on A-477279924, the reproduction sessions that keep adding new evidence. None of that depends on Google's VRP status. All of it depends on doing the work and documenting it honestly. And none of it pays in any direct sense. That is not the point. The point is that the work is worth doing, and someone has to do it.

The pause is a setback. It is not the end of the investigation.


7. What I am doing now

While the OSS VRP pause runs its course:

  • The Android VRP case remains open. I will continue to follow up on A-477279924 and the internal dependency.
  • Public documentation continues. The blog and GitHub repository are the primary record of the investigation.
  • CVE assignment proceeds through INCIBE to MITRE. This path does not depend on Google's VRP status.
  • The HackerOne dispute for Xiaomi (#4064049) remains active. The contradiction between "not applicable" and the internal ticket XS-112757 is documented.
  • New reproduction sessions continue. The finding is not static; the evidence base grows.

8. A note on the irony

The STA research documents a class of defects that arise when structured input is allowed to propagate without size constraints across processing layers. The OSS VRP pause is a different manifestation of the same underlying pattern: an unconstrained input channel (automated report generation) overwhelming a downstream processing layer (human triage), producing a cascading failure (program suspension).

The difference is that in STA, the fix is technical: bound the field, gate the transaction, degrade gracefully. In the bug bounty ecosystem, the fix is procedural: redesign intake, separate signal from noise, restore the economic asymmetry between generating a report and validating one.

Both problems are solvable. Neither will be solved by pretending the input is not there.

AI can exponentially expand the search surface, but security still depends on the ability to demonstrate causality, reproducibility, and impact.

Upstream Convergence - STA Patterns in Android and Chromium (2026)

Saturday, September 05, 2026

Upstream Convergence — STA Patterns in Android and Chromium (2026)

This article documents a series of upstream commits in Android, AndroidX, and Chromium during 2026 that implement defensive measures around the same Binder/IPC boundaries identified by the Structured Text Amplification (STA) research. While no commit explicitly references STA, the functional convergence is substantial.


1. The Pattern

The STA model describes a recurring architectural failure: structured input → serialisation → Binder/IPC → uncaught exception → crash or ANR. Over the course of 2026, multiple upstream projects have introduced mitigations that directly address this class of problem.

What follows is a non‑exhaustive but representative list of commits that target exactly the surfaces documented in the STA whitepaper.


2. Upstream Mitigations — A Family of Defences

Component Commit / Change Mechanism Date STA Relation
AOSP InputMethod a438ce172b441c8297eadde8d990ab292f5aa7d1 Introduces InputMethodSubtypeSafeList (and AbstractSafeList) to avoid TransactionTooLargeException when large lists are passed over Binder. 7 Jan 2026 (merge) Precedent: changing representation to escape Binder (byte[]/writeBlob)
AndroidX Credential Manager 393e20ae2c23c509df55058e5d7a3157a749e03b Implements LargePayloadSupport: serialises Bundle to temporary file, passes ParcelFileDescriptor instead of raw data. Triggers for responses >200 KB. 8 Apr 2026 Architectural: large IPC → FD
Chromium PDF Selection 84b615a07fc14988b46f0e362502ab4075216793 Refactors and exposes an existing MAX_SHARE_QUERY_LENGTH = 100000 safeguard (already present in SelectionPopupControllerImpl) into SelectionUtils for PDF selection (Share / Search / Translate). Note: the CL was reverted ~1.5h later for an Android Lint issue; the underlying 100 KB limit predates this commit. 5 May 2026 Architecturally related to STA-007 (PDF → Select All → Translate). Shows that Chromium treats selection size as a safety property of the Intent boundary.
AndroidX NotificationCompat 90ffa6a7b02aeefa8f38dc1e54f5740adc18e832 Fixes a TransactionTooLargeException caused by oversized images in compatibility extras. Prevents oversized compat extras from replacing already-resized native extras. 11 May 2026 Architectural: structured extras → Binder → TLE
AndroidX PdfView 8882927e7d41e678c6f03f50d4bd5950e7dc6c47 Fixes TransactionTooLargeException in onSaveInstanceState() by replacing full SelectionModel (>1.2 MB) with lightweight anchor points (~44 bytes) when crossing Binder. 14 Jul 2026 Strong architectural convergence: Class A (SavedState / large structured state → Binder → TLE → placeholder → async restoration).
Chromium Oversized Clipboard 4751a7699c8653c5a944152a4fd78fe97e878885 Adds support for “pasting oversized HTML payloads” via ContentProvider URIs instead of direct transport. Defends against confused deputy attacks. 24 Aug 2026 Architecturally related to STA-011 (Clipboard → assisted paste). Large text/HTML → redirected transport.
Chromium Native Messaging (redesign) f5c51669e832d97728da04c79dd426ac2aa49a60 Changes message representation from String to Union(byte[], SharedMemory). Explicitly targets messages that may exceed the 1 MB Binder limit and cause TransactionTooLargeException. 26 Aug 2026 Strong architectural convergence: redesigning the transport boundary itself (SharedMemory).
Chromium Native Messaging (telemetry) 931ee1abb38c9781b5b1470ba64c99afb198ed64 Adds telemetry for SentMessageSize and explicitly distinguishes TransactionTooLargeException as a failure mode. 1 Sep 2026 Strong: explicit instrumentation of the same boundary failure.

Note: None of these commits mention STA or the STA whitepaper. They are presented here as convergent engineering — independent mitigations that address the same class of problems documented by the STA research.


3. STA-007: A Clean Upstream Echo

The STA-007 vector describes a chain:

Google Drive → PDF with invisible text → Select All → Translate → TransactionTooLargeException

Chromium’s May 2026 commit (84b615a) does not introduce the 100 KB limit — it reuses and exposes an existing safeguard already present in SelectionPopupControllerImpl. The commit message explicitly references Android Intent size limits (~1 MB) as the reason for the limit.

This is not proof that Chromium acted on STA-007. But the functional alignment is so precise that an engineer reading both documents would immediately recognise the same boundary. The key observation is that Chromium was already treating selection text size as a safety property of the Intent boundary, before the STA research was published.


4. The Asymmetry: libminikin Remains Unaddressed

While multiple upstream projects have implemented defences around Binder/IPC boundaries, no equivalent global length gate has been found in libminikin for the line‑breaking path documented in STA‑017.

  • getPrevWordBreakForCache() still performs backwards scans without a hard input‑length guard.
  • The investigated optimal line-breaking path (LineBreakOptimizer::computeBreaks()) retains nested candidate-processing loops, but no public global input-length gate comparable to the IPC safeguards above was identified.
  • Only a specific hyphenation safeguard exists (words longer than 45 characters), which does not cover the general case.

Key observation: A concentrated set of mitigations is visible around serialisation, clipboard, IPC, and persistence boundaries — while the text‑layout path (libminikin) has not received the same treatment.

4.1 Why libminikin Might Be Different

Unlike Binder/IPC boundaries, which have clear size limits (1 MB) and can be instrumented or redirected, libminikin is a native layout engine with deep roots in Android’s text rendering pipeline. A hard global length gate in computeBreaks() would affect all text rendering — not just URLs or structured payloads — making it a more complex change to validate without breaking existing applications.

This does not excuse the absence of a defence, but it helps explain why the asymmetry exists.


5. Temporal Context

The commits listed above span from November 2025 to September 2026. The STA whitepaper was published on 30 July 2026.

This timeline reveals two distinct waves:

  • Before July 2026: SafeList, LargePayloadSupport, NotificationCompat, and the PDF selection refactor all predate the STA whitepaper. They show that upstream projects were already treating oversized structured payloads as a reliability/security concern.
  • After July 2026: Oversized clipboard (24 Aug), SharedMemory redesign (26 Aug), and TLE telemetry (1 Sep) occur after the STA research became public. They address surfaces that the STA whitepaper explicitly documented.

This distribution makes the hypothesis “all these changes are a reaction to STA” unsustainable. But it also makes a different claim stronger:

“STA was published during a period when upstream was already moving toward explicit size controls, alternative representation, and payload isolation at Binder boundaries. After publication, that trend continued and added changes to surfaces specifically documented by STA.”


6. Summary: Mitigated vs. Unmitigated Surfaces

Surface Mitigation Visible? Mechanism
InputMethod → Binder (large lists) ✅ Yes SafeList → byte[]/writeBlob
Large IPC (Credential Manager) ✅ Yes LargePayloadSupport (FD)
PDF → Share / Search / Translate ✅ Yes Truncation (100 KB limit, refactored into SelectionUtils)
NotificationCompat (oversized images) ✅ Yes Prevents oversized compat extras from replacing native ones
SavedState (PdfView) ✅ Yes Anchor points (~44 bytes) + async restoration
Oversized Clipboard ✅ Yes ContentProvider URI
Native Messaging ✅ Yes SharedMemory + telemetry
libminikin (LineBreakOptimizer) ❌ Not found No global length gate in the investigated path

7. What This Convergence Means

The upstream commits listed above represent a family of defensive engineering decisions, all targeting the same underlying problem:

Large structured payload → Binder/IPC → TransactionTooLargeException → Crash or ANR

The mitigations vary by component, but they follow a consistent pattern:

  • Constrain: limit input size before it reaches the boundary (Chromium PDF selection).
  • Redirect: move payload out of Binder (LargePayloadSupport → FD; Oversized Clipboard → ContentProvider).
  • Replace: replace full state with lightweight placeholders (PdfView → anchor points).
  • Observe: instrument the failure to understand its prevalence (Native Messaging telemetry).

The strongest evidence is not that individual fixes resemble individual STA vectors. It is that multiple upstream projects independently apply the same defensive principle: constrain, redirect, replace, or observe data before an oversized structured payload becomes a failure at an IPC boundary.


8. Conclusion

The STA model identified an architectural pattern: structured input that crosses Binder/IPC boundaries without size validation can cause persistent crashes and ANRs. The upstream commits documented in this article show that:

  1. Multiple components (AndroidX, AOSP, Chromium) have introduced mitigations at exactly those boundaries.
  2. The timing (2026) and the mechanisms (constrain, redirect, replace, observe) align with the surfaces described in the STA whitepaper.
  3. No causal link is claimed — but the functional convergence is substantial and observable.
  4. libminikin remains an outlier, with no visible global length gate for the investigated line‑breaking path.

Whether this convergence is coincidental or a response to the STA research is not something this article can determine. What is clear is that the industry is moving toward defensive patterns that match the STA diagnosis — and that the asymmetry with libminikin persists.


STA: 48 Hours Later – The Chrome Correlation and the VRP Case Status

Saturday, August 01, 2026

STA: 48 Hours Later – The Chrome Correlation and the VRP Case Status

Published on July 31, 2026 · Post‑whitepaper update
🔗📊🧩 STA – Chrome Alignment Map
Shared architectural surfaces between the whitepaper and the July 2026 patches

These are not the same bugs. What we are seeing is a shared architectural surface:

STA-020 remains unpatched for four years.

  • Chrome patched its own side of the pipeline — Print Preview, Clipboard, Views, Skia, WebView, UI.
  • Android still has the same architectural pipeline exposed, with no public fixes for libminikin, SystemUI, or FragmentManager.restoreAllState().

The patches in Chrome exist. The same pipelines surfaces in Android remain open.

The Chrome fixes are public. Equivalent Android architectural surfaces remain publicly unpatched, based on the information available at the time of writing. This suggests that the underlying architectural bottlenecks identified by STA remain relevant and deserve further scrutiny.


📄 Full whitepaper: lostmon.blogspot.com
#STA #AndroidSecurity #Chrome

It has been 48 hours since the publication of the Structured Text Amplification (STA) whitepaper.

But the most interesting development happened over the last two days. Chrome’s July fixes harden several components that sit on the same processing paths STA describes (clipboard, print/preview, views/UI, WebView, document/Drive flows). Those are shared surfaces. The concrete Chrome CVEs are mostly memory-safety or validation bugs in the browser; STA documents missing limits and safe degradation on the Android framework side of related pipelines (Binder/SavedState, SystemUI, libminikin). Same corridor, different failure modes — and the framework side still has no public STA mitigations.

The Alignment Map: Chrome CVEs vs. STA

The table below correlates Chrome CVEs with the STA pipelines/vectors documented in the whitepaper. Confidence levels are indicated with traffic‑light markers:

  • 🟢 High: The component is identical to or directly implements the same surface described in STA.
  • 🟡 Medium: The component shares the same architectural pipeline, but the exact failure mode may differ.
  • ⚪ Low: Conceptually related but not directly comparable.
Chrome CVE Component Potential STA Vector Confidence Rationale
CVE-2026-17679 Print Preview STA-010 🟢 High Both involve document/text processing before printing.
CVE-2026-17766 Clipboard STA-011 🟢 High Clipboard handling is explicitly part of the STA surface.
CVE-2026-17670 Views STA-020 🟢 High Views is the UI layer where much of the STA pipeline terminates.
CVE-2026-17699 Views STA-020 🟢 High Same architectural layer.
CVE-2026-17702 Skia STA-017 🟢 High Skia is part of the graphics pipeline downstream from libminikin.
CVE-2026-17745 Skia STA-017 🟢 High Same graphics pipeline.
CVE-2026-17757 Skia STA-017 🟢 High Same graphics pipeline.
CVE-2026-15766 Skia STA-017 🟡 Medium Another recent Skia issue in the same rendering path.
CVE-2026-17698 UI STA-017 / STA-020 🟡 Medium The UI layer processes structured text before rendering it.
CVE-2026-17722 WebView STA-027 (general) 🟡 Medium WebView participates in several propagation scenarios described in STA.
CVE-2026-17690 PDF STA Document Pipeline 🟡 Medium Document processing with structured input.
CVE-2026-17803 Save to Drive STA Deep Link / Drive 🟡 Medium Similar to the Drive → Chrome → Android propagation chain.
Methodological note: I am not asserting that these CVEs are the same bugs as the STA vectors. I am identifying functional overlap in the processing pipelines (Views, Skia, Clipboard, Print Preview, WebView, UI) that intersect with the surfaces described in the whitepaper.

Google Knew, and Google Patched (but Not on Android)

What makes this table significant is not any single CVE, but the recurring pattern across the Chrome fixes from May and June 2026:

  • “Insufficient validation of untrusted input” in Print Preview
  • “Insufficient validation of untrusted input” in Clipboard
  • “Use after free” in Views
  • “Inappropriate implementation” in Skia
  • “Use after free” in UI / Input
  • “Object lifecycle issue” in WebView

Google patched its own browser to protect it from flaws that are structurally identical to those I documented in Android. Yet the July Android Security Bulletin (published July 6) contained no patches for any of these surfaces.

The conclusion is clear: Google has the internal fix (AOSP CL 3989977). It patched Chrome. But the base platform — the one used by 2.5 billion devices — remains exposed.

Status of the VRP Case (A-477279924)

The VRP case A-477279924 remains open, blocked on internal dependency 477593694 (which, based on all available evidence, corresponds to AOSP CL 3989977). I have added the correlation table as a comment in that case, along with the following note:

“I am sharing this in case it helps accelerate internal triage or identifies surfaces that may still require backporting to the Android framework. This is intended as a triage aid, not as a claim of direct causation.”

Now the ball is in Google’s court. They have the fix. They patched Chrome. And they know exactly where the architectural overlap lies.

What This Means for Users

  • No public patch for Android as of today (July 31, 2026). The next security bulletin is August 3.
  • If Google does not include these fixes in August, the media pressure will intensify.
  • Blog de‑indexation (from ~200 pages to just 4 indexed) remains unexplained.

The Full Whitepaper

All technical details, stack traces, vector tables, and patch recommendations are available in the full whitepaper:

📄 Read the whitepaper

libminikin: 10 años de vulnerabilidad en el núcleo de Android

Friday, July 10, 2026
libminikin: "Un comportamiento heredado del motor de composición de texto de Android"
Análisis forense del código fuente de AOSP · 6 archivos · 5 capas vulnerables · Una década de deuda técnica

📌 Este artículo es una extensión de mi análisis original: "Algorithmic DoS en libminikin.so – Cómo un texto de 70 KB puede congelar casi cualquier app Android" (24 de junio de 2026).

🔥 10 AÑOS. 10 ARCHIVOS. MAS DE 5 CAPAS VULNERABLES.

El análisis del código fuente de Android (AOSP) confirma que libminikin.so tiene un fallo de diseño sistémico presente desde 2013.

  • 10 archivos vulnerables en el repositorio de AOSP
  • 5 capas del pipeline de texto sin validación de entrada
  • 10 años de deuda técnica documentada (2013 → 2026)
  • 2.500 millones de dispositivos en riesgo
  • Google lo sabe desde 2016 (CVE-2016-2414) y no lo ha arreglado

1. Resumen ejecutivo

Desde la publicación del artículo original sobre el Algorithmic DoS en libminikin.so, he continuado investigando el código fuente de Android (AOSP) para comprender la magnitud real del problema.

Lo que he encontrado es más grave de lo que imaginaba. No se trata de un bug aislado en una función concreta. Es un fallo de diseño sistémico presente en 6 archivos diferentes, distribuido en 5 capas del pipeline de texto, y que ha estado en el repositorio de AOSP desde 2013.


2. Issues públicos de Google (2020–2026)

La siguiente tabla recopila los issues públicos del Google Issue Tracker que documentan problemas en libminikin y el pipeline de texto de Android. Todos ellos fueron cerrados sin una solución estructural.

Issue Año Descripción Estado Enlace
#161830416 2020 Crash en LayoutCache::getOrCreate con traza completa (FreeType → Minikin → HarfBuzz) Won't Fix Ver issue
#167014931 2020 Crash por Float.POSITIVE_INFINITY en LayoutPiece::LayoutPiece Fixed Ver issue
#188985643 2021 SIGSEGV en FontFamily::getClosestMatch en Samsung Galaxy J6+ con fuente personalizada Won't Fix Ver issue
#40268980 (Chromium 1447465) 2023 ANR en Chrome por LayoutCache::getOrCreate reportado por ingeniero de Samsung Won't Fix Ver issue
#477202817 2026 Reporte formal al Chrome VRP — DoS persistente por URL larga. Cerrado como "Intended Behavior" Won't Fix Ver issue
#524288518 2026 Reporte específico de libminikin al Android VRP — cerrado como "out of scope" Out of Scope (interno de Google)
#531319203 Jul 2026 system_server boot loop por imagen grande en BitmapCache — mismo patrón Assigned Ver issue

🔴 Patrón común: Google ha cerrado sistemáticamente estos reportes sin abordar la causa raíz. Solo ha arreglado el caso trivial (#167014931) porque el trigger era evidente (Float.POSITIVE_INFINITY).


3. Análisis del código fuente: 6 archivos vulnerables

He analizado el código fuente de Minikin en el repositorio de AOSP (frameworks/minikin/) y he identificado seis archivos clave que contienen vulnerabilidades de diseño.

Archivo Año Problema principal Función vulnerable
FontFamily.cpp 2013 Punteros nulos en getClosestMatch getClosestMatch()
Layout.cpp 2013 Procesa directamente textos largos sin caché doLayoutWord()
OptimalLineBreaker.cpp 2015 Knuth-Plass O(n²) sin límites computeBreaks()
GreedyLineBreaker.cpp 2017 Algoritmo voraz O(n²) en el peor caso processLineBreak()
LineBreaker.cpp 2018 Decisión entre algoritmos sin validar longitud breakIntoLines()
LayoutCache.h 2018 Caché sin límite de tamaño por entrada getOrCreate()

4. Funciones vulnerables y código exacto

4.1 LineBreaker::breakIntoLines — Sin validación de longitud

Archivo: frameworks/minikin/libs/minikin/LineBreaker.cpp (2018)

LineBreakResult breakIntoLines(const U16StringPiece& textBuffer, BreakStrategy strategy,
                               HyphenationFrequency frequency, bool justified,
                               const MeasuredText& measuredText, const LineWidth& lineWidth,
                               const TabStops& tabStops, bool useBoundsForWidth) {
    if (strategy == BreakStrategy::Greedy || textBuffer.hasChar(CHAR_TAB)) {
        return breakLineGreedy(textBuffer, measuredText, lineWidth, tabStops,
                               frequency != HyphenationFrequency::None, useBoundsForWidth);
    } else {
        return breakLineOptimal(textBuffer, measuredText, lineWidth, strategy, frequency, justified,
                                useBoundsForWidth);
    }
}

🔴 Vulnerabilidad: No hay comprobación de textBuffer.size(). Si el texto es de 70KB, se ejecuta breakLineOptimal o breakLineGreedy sin límite.

4.2 OptimalLineBreaker::computeBreaks — O(n²) sin límites

Archivo: frameworks/minikin/libs/minikin/OptimalLineBreaker.cpp (2015)

LineBreakResult LineBreakOptimizer::computeBreaks(const OptimizeContext& context,
                                                  const U16StringPiece& textBuf,
                                                  const MeasuredText& measuredText,
                                                  const LineWidth& lineWidth,
                                                  BreakStrategy strategy, bool justified,
                                                  bool useBoundsForWidth) {
    // ... algoritmo de programación dinámica Knuth-Plass
    // SIN validación de longitud de entrada
    // Complejidad O(n²) en el peor caso
}

Pero hay un matiz que el código revela: hay una poda activa (active = j + 1) y una optimización bestHope explícitamente comentada como tal: Cpp Esto significa que el algoritmo no es un O(n²) puro sin ninguna mitigación — tiene un mecanismo de poda que en la práctica reduce trabajo cuando delta mayor que 0 (la línea se desborda), avanzando el puntero active. El peor caso teórico sigue siendo O(n²) (cuando casi todos los candidatos permanecen "activos" simultáneamente, como pasaría con una URL sin espacios donde casi cualquier punto de ruptura es candidato).

if (jScore + bestHope >= best) continue;

🔴 Vulnerabilidad: El algoritmo Knuth-Plass tiene complejidad O(n²). Para 70.000 caracteres, son ~4.9 mil millones de operaciones.

4.3 GreedyLineBreaker::processLineBreak — Bucles anidados

Archivo: frameworks/minikin/libs/minikin/GreedyLineBreaker.cpp (2017)

void GreedyLineBreaker::processLineBreak(uint32_t offset, WordBreaker* breaker,
                                         bool doHyphenation) {
    while (isWidthExceeded() || overhangExceedLineLimit(Range(getPrevLineBreakOffset(), offset))) {
        if (tryLineBreakWithWordBreak()) {
            continue;  // El bucle puede ejecutarse muchas veces
        }
        if (doHyphenation && tryLineBreakWithHyphenation(...)) {
            // ...
        }
    }
}

🔴 Vulnerabilidad: Bucle while con llamadas a funciones que recorren el texto. Complejidad O(n²) en el peor caso.

4.4 LayoutCache::getOrCreate — Procesamiento directo sin caché

Archivo: frameworks/minikin/include/minikin/LayoutCache.h (2018)

template <typename F>
void getOrCreate(const U16StringPiece& text, const Range& range, const MinikinPaint& paint,
                 bool dir, StartHyphenEdit startHyphen, EndHyphenEdit endHyphen,
                 bool boundsCalculation, F& f) {
    LayoutCacheKey key(text, range, paint, dir, startHyphen, endHyphen);
    if (range.getLength() >= CHAR_LIMIT_FOR_CACHE) {
        // ¡PROCESAMIENTO DIRECTO! SIN CACHÉ → BLOQUEO UI
        LayoutPiece piece(text, range, dir, paint, startHyphen, endHyphen);
        // ...
        return;
    }
    // ...
}

🔴 Vulnerabilidad: Los textos largos no se almacenan en caché. Se procesan desde cero cada vez que se renderizan.


5. El pipeline completo: 5 capas de fragilidad

1. LineBreaker.cpp (2018) — breakIntoLines()
   └── Decide entre Greedy y Optimal SIN validar longitud
         │
2. OptimalLineBreaker.cpp (2015) / GreedyLineBreaker.cpp (2017)
   └── Algoritmo O(n²) SIN límites de entrada
         │
3. Layout.cpp (2013) — doLayoutWord()
   └── Llama a LayoutCache SIN verificar tamaño
         │
4. LayoutCache.h (2018) — getOrCreate()
   └── Si texto > CHAR_LIMIT_FOR_CACHE → procesa DIRECTAMENTE
         │
5. HarfBuzz (hb_shape)
   └── Renderizado de glifos → O(n²) o peor
         │
         ▼
   UI BLOQUEADA (5-16 segundos)

🔴 Todas las capas son vulnerables. Ninguna valida la longitud del texto de entrada.


🧠 El Pipeline de Amplificación de Minikin: Anatomía de un Fallo de Diseño de 13 Años

Aquí profundizo en el pipeline completo y en cómo cada capa amplifica el payload hasta convertir 70KB en un bloqueo de 16 segundos.


El motor de layout de texto de Android (Minikin) contiene un fallo de diseño sistémico que permite que un texto de tan solo 70.000 caracteres (aproximadamente 70KB) bloquee el hilo de interfaz de usuario durante 5-16 segundos, provocando ANR en cualquier aplicación que muestre texto sin truncar.

El problema no reside en una única función, sino en más de 10 archivos y 15 funciones que conforman el pipeline de procesamiento de texto. Cada capa del pipeline amplifica el coste computacional sin aplicar ningún tipo de validación de longitud o límite de entrada.

🔴 Dato clave: El código más antiguo data de 2013. Google ha tenido más de 13 años para arreglar esto.


🧠 El esquema de amplificación: 10 capas de fragilidad

Un texto de 70KB con una estructura específica (/code> repetido) activa una cascada de amplificación en la que cada capa del pipeline multiplica el coste computacional:

70KB de entrada
      │
      ▼
 ┌─────────────────────────────────────────────────────────────┐
 │ CAPA 1: LineBreaker.cpp (2018)                              │
 │ breakIntoLines() decide entre Greedy y Optimal             │
 │ SIN validar longitud → pasa 70KB al siguiente paso          │
 └─────────────────────────────────────────────────────────────┘
      │
      ▼
 ┌─────────────────────────────────────────────────────────────┐
 │ CAPA 2: OptimalLineBreaker.cpp (2015) / GreedyLineBreaker  │
 │ computeBreaks() / processLineBreak()                       │
 │ Algoritmo O(n²) → 70.000² = 4.900.000.000 iteraciones      │
 └─────────────────────────────────────────────────────────────┘
      │
      ▼
 ┌─────────────────────────────────────────────────────────────┐
 │ CAPA 3: Layout.cpp (2013)                                   │
 │ doLayoutWord() llama a LayoutCache SIN verificar tamaño    │
 └─────────────────────────────────────────────────────────────┘
      │
      ▼
 ┌─────────────────────────────────────────────────────────────┐
 │ CAPA 4: LayoutCache.h (2018)                                │
 │ getOrCreate(): si texto > CHAR_LIMIT_FOR_CACHE             │
 │ → procesa DIRECTAMENTE, sin caché                         │
 └─────────────────────────────────────────────────────────────┘
      │
      ▼
 ┌─────────────────────────────────────────────────────────────┐
 │ CAPA 5: LayoutCore.cpp (2018)                               │
 │ LayoutPiece() constructor → hb_shape (HarfBuzz)            │
 │ HarfBuzz tiene complejidad O(n²) o peor                    │
 └─────────────────────────────────────────────────────────────┘
      │
      ▼
 ┌─────────────────────────────────────────────────────────────┐
 │ CAPA 6: Hyphenator.cpp (2015)                               │
 │ hyphenateFromCodes() → bucles anidados O(n²)               │
 └─────────────────────────────────────────────────────────────┘
      │
      ▼
 ┌─────────────────────────────────────────────────────────────┐
 │ CAPA 7: Measurement.cpp (2015)                              │
 │ getOffsetForAdvance() / distributeAdvances() → O(n²)       │
 └─────────────────────────────────────────────────────────────┘
      │
      ▼
 ┌─────────────────────────────────────────────────────────────┐
 │ CAPA 8: WordBreaker.cpp (2015)                              │
 │ detectEmailOrUrl() / findNextBreakInEmailOrUrl() → O(n)   │
 └─────────────────────────────────────────────────────────────┘
      │
      ▼
 ┌─────────────────────────────────────────────────────────────┐
 │ CAPA 9: FontCollection.cpp (2013)                           │
 │ getGlyphScore() → llama a hb_shape() nuevamente           │
 └─────────────────────────────────────────────────────────────┘
      │
      ▼
 ┌─────────────────────────────────────────────────────────────┐
 │ CAPA 10: FontFamily.cpp (2013)                              │
 │ getClosestMatch() → punteros nulos → SIGSEGV               │
 └─────────────────────────────────────────────────────────────┘
      │
      ▼
   🔥 UI BLOQUEADA (5-16 segundos)

🔴 10 capas. 10 archivos. Ninguna valida la longitud del texto de entrada.


📂 Tabla completa de archivos y funciones vulnerables

Archivo Año Función Complejidad Problema
LineBreaker.cpp2018breakIntoLines()O(1)No valida longitud de entrada
OptimalLineBreaker.cpp2015computeBreaks()O(n²)Knuth-Plass sin límites
GreedyLineBreaker.cpp2017processLineBreak()O(n²)Bucles anidados sin límites
Layout.cpp2013doLayoutWord()O(n)Llama a LayoutCache sin verificar tamaño
LayoutCache.h2018getOrCreate()O(n)CHAR_LIMIT_FOR_CACHE → procesa directamente
LayoutCore.cpp2018LayoutPiece()O(n²)Llama a hb_shape (HarfBuzz) sin límites
Hyphenator.cpp2015hyphenateFromCodes()O(n²)Bucles anidados sin límites
Measurement.cpp2015getOffsetForAdvance()O(n²)Bucles anidados sin límites
Measurement.cpp2015distributeAdvances()O(n²)Bucles anidados sin límites
WordBreaker.cpp2015detectEmailOrUrl()O(n)Recorre texto sin límites
WordBreaker.cpp2015findNextBreakInEmailOrUrl()O(n)Recorre texto sin límites
FontCollection.cpp2013getGlyphScore()O(n²)Llama a hb_shape sin límites
FontCollection.cpp2013itemize()O(n)Recorre texto sin límites
FontFamily.cpp2013getClosestMatch()O(n)Puntero nulo → SIGSEGV

📊 10 archivos. 15 funciones. 10 años de código vulnerable. 13 años desde el primer archivo.


🔬 Amplificación paso a paso: Cómo 70KB pieden convertirse en 5 mil millones de operaciones

Paso 1: Entrada (70KB)

El payload es una URL de 70.000 caracteres con el patrón [PAYLOAD] repetido:

https://example.com/[PAYLOAD]

Paso 2: LineBreaker::breakIntoLines (2018)

if (strategy == BreakStrategy::Greedy || textBuffer.hasChar(CHAR_TAB)) {
    return breakLineGreedy(...);   // ← No hay validación de longitud
} else {
    return breakLineOptimal(...);  // ← Tampoco hay validación
}

Amplificación: Decide el algoritmo sin comprobar la longitud del texto.

Paso 3: OptimalLineBreaker::computeBreaks (2015) — O(n²)

LineBreakResult LineBreakOptimizer::computeBreaks(...) {
    // ... algoritmo de programación dinámica Knuth-Plass
    // SIN validación de longitud de entrada
    // Complejidad O(n²) en el peor caso
}

Amplificación: Para n=70.000 → 4.900.000.000 iteraciones.

Paso 4: Layout::doLayoutWord (2013)

float Layout::doLayoutWord(...) {
    // ...
    LayoutCache::getInstance().getOrCreate(textBuf, range, paint, isRtl, startHyphen, endHyphen,
                                           boundsCalculation, f);
    // ...
}

Amplificación: Llama a LayoutCache sin verificar el tamaño del texto.

Paso 5: LayoutCache::getOrCreate (2018)

if (range.getLength() >= CHAR_LIMIT_FOR_CACHE) {
    LayoutPiece piece(text, range, dir, paint, startHyphen, endHyphen);
    // PROCESAMIENTO DIRECTO → SIN CACHÉ → BLOQUEO UI
    return;
}

Amplificación: Los textos largos no se almacenan en caché. Se procesan desde cero cada vez.

Paso 6: LayoutPiece constructor (2018)

LayoutPiece::LayoutPiece(...) {
    // ...
    hb_shape(hbFont.get(), buffer.get(), features.empty() ? NULL : &features[0],
             features.size());
    // ...
}

Amplificación: hb_shape (HarfBuzz) puede tener complejidad O(n²) o peor.

Paso 7: Hyphenator::hyphenateFromCodes (2015)

void HyphenatorCXX::hyphenateFromCodes(...) const {
    for (size_t i = 0; i < len - 1; i++) {
        for (size_t j = i; j < len; j++) {
            // BUCLES ANIDADOS SIN LÍMITES
        }
    }
}

Amplificación: Bucles anidados O(n²) que se ejecutan para cada palabra.

Paso 8: Measurement::getOffsetForAdvance / distributeAdvances (2015)

size_t getOffsetForAdvance(...) {
    for (size_t i = start; i < max; i++) { /* ... */ }
    for (size_t i = searchStart; i <= max; i++) { /* ... */ }
}

Amplificación: Bucles anidados O(n²) en el peor caso.

Paso 9: WordBreaker::detectEmailOrUrl (2015)

void WordBreaker::detectEmailOrUrl() {
    for (i = mLast; i < mTextSize; i++) { /* ... */ }
}

Amplificación: Bucle O(n) que recorre el texto sin límites.

Paso 10: FontCollection::getGlyphScore (2013)

uint32_t getGlyphScore(...) {
    hb_shape(font.get(), buffer.get(), nullptr, 0);  // O(n²)
}

Amplificación: Llama a hb_shape para cada fuente evaluada.

🔴 Resultado: 70KB → 5 mil millones de iteraciones → 16 segundos de bloqueo → ANR.


⚡ El payload mínimo

Para activar todo el pipeline de amplificación, se necesita un texto con:

  • Longitud: > 70.000 caracteres
  • Estructura: Caracteres que multipliquen los puntos de decisión:
    • # → duplica decisiones de salto
    • / → cada barra añade un punto de ruptura
    • % → expansión UTF-8 → UTF-16
    • € → propiedades de salto ambiguas

Payload óptimo:

[PAYLOAD]

Repetido hasta alcanzar 70.000 caracteres.


📅 Cronología (2013–2026)

Año Evento Lo que demuestra
2013FontCollection.cpp, FontFamily.cpp, Layout.cpp creadosEl código vulnerable existe desde hace 13 años
2015OptimalLineBreaker.cpp, Hyphenator.cpp, Measurement.cpp, WordBreaker.cpp creadosEl pipeline de amplificación se completa
2016CVE-2016-2414 — DoS en MinikinGoogle sabía que Minikin era vulnerable y lo arregló
2017GreedyLineBreaker.cpp creadoSe añade una capa más de amplificación
2018LineBreaker.cpp, LayoutCore.cpp, LayoutCache.h creadosEl pipeline alcanza 10 capas
2020Issue #161830416 — crash en LayoutCacheGoogle recibió evidencia, la ignoró
2021Issue #188985643 — SIGSEGV en SamsungGoogle lo ignoró porque no se reproducía en Pixel
2023Chromium 1447465 — ANR en Chrome reportado por SamsungGoogle lo cerró con "who knows"
2026Reporte VRP — 31 vectores documentadosGoogle lo cerró "out of scope"
2026Boletín de julio — sin parcheGoogle sigue ignorando el problema

🔴 13 años de código vulnerable. 10 archivos. 15 funciones. Google no lo ha arreglado.


El pipeline de layout de texto de Android está compuesto por más de 10 archivos y 15 funciones que, en conjunto, forman un sistema de amplificación de DoS. Cada capa multiplica el coste computacional sin aplicar validación de longitud, permitiendo que un texto de 70KB bloquee la UI durante 5-16 segundos.

Google ha tenido 13 años para arreglar esto. Los archivos vulnerables datan de 2013 (FontCollection.cpp, FontFamily.cpp, Layout.cpp) y se han ido añadiendo más capas a lo largo de los años (2015, 2017, 2018). Ninguna de ellas ha sido parcheada para abordar el problema de la validación de entrada.

6. FontFamily.cpp: el origen del SIGSEGV en Samsung

El archivo FontFamily.cpp (creado en 2013) contiene la función getClosestMatch, responsable del SIGSEGV documentado en issue #188985643 (2021, Samsung Galaxy J6+).

FakedFont FontFamily::getClosestMatch(FontStyle style, const VariationSettings& axes) const {
    if (features::typeface_redesign_readonly()) {
        int bestIndex = 0;
        Font* bestFont = mFonts[bestIndex].get();  // ← ¡POSIBLE PUNTERO NULO!
        // ...
    }
    // ...
}

🔴 Problema: mFonts puede estar vacío. En producción, MINIKIN_ASSERT no se activa y el programa accede a memoria inválida → SIGSEGV.

Google respondió:

"I haven't receive any crash report at this function on Pixel devices, and likely it is not actionable to me only with this stack trace."


7. LayoutCache.h: el amplificador silencioso

El archivo LayoutCache.h (creado en 2018) es donde la vulnerabilidad se vuelve persistente.

if (range.getLength() >= CHAR_LIMIT_FOR_CACHE) {
    LayoutPiece piece(text, range, dir, paint, startHyphen, endHyphen);
    // PROCESAMIENTO DIRECTO → SIN CACHÉ → BLOQUEO UI
    return;
}

🔴 Esto significa que:

  1. Los textos largos no se almacenan en caché.
  2. Cada vez que se renderizan, se procesan desde cero.
  3. El bloqueo de UI ocurre cada vez que se muestra el texto.

8. Evidencia forense: los números no mienten

Longitud del texto Iteraciones aprox. Tiempo de bloqueo
1.000 caracteres ~1.000² = 1.000.000 < 100 ms
10.000 caracteres ~10.000² = 100.000.000 ~500 ms - 1 s
70.000 caracteres ~70.000² = 4.900.000.000 5 - 16 segundos

🔴 Un texto de 70KB genera casi 5 mil millones de operaciones en el hilo UI.


9. La cronología de la libminikin (2013–2026)

Año Evento Lo que demuestra
2013 FontFamily.cpp y Layout.cpp creados El código vulnerable existe desde hace 11 años
2016 CVE-2016-2414 — DoS en Minikin Google sabía que Minikin era vulnerable y lo arregló
2020 Issue #161830416 — crash en LayoutCache Google recibió evidencia, la ignoró
2021 Issue #188985643 — SIGSEGV en Samsung Google lo ignoró porque no se reproducía en Pixel
2023 Chromium 1447465 — ANR en Chrome reportado por Samsung Google lo cerró con "who knows"
2026 Reporte VRP — libminikin ANR y crash loop Google lo cerró "out of scope"
Jul 2026 Boletín de seguridad sin parche Google sigue ignorando el problema

🔴 Google ha tenido más de 10 años para arreglar esto. Ha arreglado los casos triviales e ignorado los complejos.


10. La contradicción del VRP: $250 y "out of scope"

El timeline:

  • 20 de enero de 2026: Reporte formal al Android VRP (27 vectores).
  • Google paga $250 por el caso Binder/IPC (A-477279924).
  • 15 de junio de 2026: Google cierra el reporte específico de libminikin como "out of scope" (524288518).
  • 16 de junio de 2026: Apelación enviada para STA-015-DL (CVSS 8.6) Google cierra el reporte de apelación específico de libminikin como "NoT reproducible"
  • 6 de julio de 2026: Boletín de seguridad de julio — sin parche para ningún vector.

💡 La contradicción: Google pagó una recompensa por la investigación, pero cerró el reporte más grave como "out of scope". Si está fuera de alcance, ¿por qué pagan?

Por primera vez, después de más de 400 vulnerabilidades descubiertas y documentadas a lo largo de estos años, he sido recompensado con 250 dólares por la primera parte de mi trabajo. Ni la cantidad, ni la forma en que se ha gestionado la segunda parte de la investigación reflejan el alcance ni la gravedad de las vulnerabilidades documentadas

Matemáticamente, teniendo en cuenta que pueden ser 2.500 millones de dispositivos afectados, eso es 0,0000001 dólares por dispositivo. Es decir, menos de una diezmilésima parte de un céntimo por cada teléfono vulnerable.


11. Conclusión: 10 años de código vulnerable

El análisis del código fuente de AOSP confirma que la vulnerabilidad en libminikin no es un bug aislado, sino un fallo de diseño sistémico presente en el núcleo de Android desde 2013.

🔴 Lo que sabemos ahora:

  • 6 archivos vulnerables en AOSP.
  • 5 capas del pipeline de texto sin validación.
  • 10 años de evidencia documentada (2013 → 2026).
  • Google ha tenido más de 10 años para arreglar esto.
  • Ha arreglado los casos triviales (CVE-2016-2414) e ignorado los complejos.

El 30 de julio de 2026 publicaré el whitepaper completo con los 31 vectores documentados, las trazas nativas completas y el análisis forense del código fuente. Si tu aplicación usa TextView, ya estás avisado.

📌 Para desarrolladores (mitigación inmediata):

private static final int MAX_SAFE_LENGTH = 8192;
String safe = text.length() > MAX_SAFE_LENGTH 
    ? text.substring(0, MAX_SAFE_LENGTH) + "…" 
    : text;
textView.setText(safe);

12. Referencias y enlaces

Artículos del investigador

Issues públicos de Google

Código fuente de AOSP

🔥 1.6 Minikin es un síntoma de una brecha de resiliencia sistémica

La vulnerabilidad de libminikin no es un bug aislado. Es un síntoma de una brecha de resiliencia sistémica en el framework de Android: la ausencia de un mecanismo estandarizado de "safe fallback" para manejar datos que superan los límites del sistema.

El mismo patrón aparece en al menos diez componentes distintos del sistema operativo Android:

Componente Modo de fallo Impacto
FragmentManager No captura TransactionTooLargeException Bucle de crash permanente
TaskPersister Persiste el estado corrupto en disco El bucle de crash sobrevive a reinicios
SystemUI Lee TaskPersister sin validación Bucle de crash → pantalla de bloqueo
Print Service Sin validación del tamaño del documento SystemUI crash
ClipboardManager Serializa todo el contenido del portapapeles sin límites SystemUI crash
Binder Límite de 1MB sin safe fallback Crash de la app
libminikin.so Sin validación de longitud de entrada ANR (5–16s)
LayoutCache CHAR_LIMIT_FOR_CACHE fuerza el procesamiento directo Amplifica el DoS
BitmapCache Sin validación del tamaño de imagen (issue #531319203) Crash de system_server → bucle de arranque
MediaSession Sin validación del tamaño de la carátula Crash de system_server → bucle de arranque

🔴 Diez componentes. Diez modos de fallo diferentes. El mismo patrón subyacente: sin validación de entrada antes del procesamiento, y sin safe fallback cuando se superan los límites.

Esto no es un bug de Minikin. Es un fallo de diseño del framework de Android que ha estado presente durante más de una década, afectando a componentes que van desde la capa de aplicación hasta el servidor central del sistema. Google ha añadido capas de complejidad a Minikin sin abordar la causa raíz, y ha descartado los informes de estos problemas como "fuera de alcance" o "comportamiento intencionado" durante años.

Minikin no es la enfermedad. Es un síntoma.



#Lostmon #Android #AOSP #Ciberseguridad #MobileSecurity #SystemUI #libminikin #STA #StructuredTextAmplification #BugBounty #GoogleVRP #Xiaomi #HackerOne #SaludMental #InvestigaciónIndependiente #BojosXtu
Manuel Garcia Peña (Lostmon) · lostmon@gmail.com · lostmon.blogspot.com
Whitepaper completo: 30 de julio de 2026
 

Browse

About:Me

My blog:http://lostmon.blogspot.com
Mail:Lostmon@gmail.com
Lostmon Google group
Lostmon@googlegroups.com

La curiosidad es lo que hace
mover la mente...

Friends