91³Ô¹ÏÍø

Watch CBS News

Exclusive
CBS Mornings

China uses "dark fleet" to buy oil from Iran and evade U.S. sanctions in international waters

A CBS News investigation has revealed that China is still secretly buying Iranian oil and evading U.S. sanctions by using what's known as a "dark fleet" to transfer oil from ship to ship in the middle of the sea.

Over the years, the U.S. has implemented heavy sanctions on Iranian industries, including trying to stop tankers used to transfer Iranian oil to China, which could help fund Iranian nuclear development programs. On Wednesday, the Treasury Department imposed additional sanctions, which Washington called the most extensive action of its kind since 2018.

Recently, a CBS News crew set off from Singapore, one of the busiest shipping ports in the world, to head more than 80 nautical miles away in international waters to see how the "dark fleet" operates.

"As long as there's a supply, there will be a demand for this discounted oil," said Charlie Brown, a former U.S. Navy officer who's now a senior adviser with United Against Nuclear Iran, who is advising the U.S. government.

The supply is Iran, the demand is China, and this mutually beneficial relationship, which has long angered the United States, plays out off the coast of Malaysia in the Riau archipelago, an area the size of New York City.

"This is 'dark fleet' parking central," said Brown, who's been monitoring the "dark fleet" for years.

He described one ship, the Tifani, as "a well-known 'dark fleet' tanker that's always been out here on a regular basis."

The tankers, full of oil, sail from the Persian Gulf through the Strait of Malacca to the Riau archipelago. There, they transfer the crude to ships bound for China, which buys 90% of Iran's oil.

A map shows how Iranian oil is transported to China.
A map shows how Iranian oil is transported to China. CBS

During the CBS News crew's journey, four ship-to-ship transfers were happening in plain sight.

These "dark fleet" tankers — all with their transponders switched off — clearly do not want to be identified.

"Both ships have a net or something, a tarp, deployed over the stern, covering the name and identification number — it's obvious deceptive practice," Brown said.

Further analysis revealed one ship was the elusive Stellar Oracle, laden with Iranian oil. It was placed on the U.S. sanctions list in May.

Close by, another ship-to-ship transfer was underway involving the Alps — not its real name — filled with Iranian crude that was also sanctioned in May. The receiving vessel Eon, which is not on any list, was caught in the act — a new sanctions violator.

The Alps and the Eon are seen in the Riau archipelago.
The Alps and the Eon are seen in the Riau archipelago. CBS

According to a congressional report last year, this trade generated as much as $70 billion for Iran, propping up the regime and its nuclear weapons program. The Trump administration has imposed multiple rounds of sanctions on this trade this year, but it's having little effect. China doesn't recognize the unilateral U.S. sanctions on Iran and says that its trade with Iran is legitimate.

By the end of the day, 12 ship-to-ship transfers were recorded in the Riau archipelago — an unprecedented number and a clear indication Iran and China are only ramping up this illicit activity.

View CBS News In
CBS News App Open
Chrome Safari Continue
const link = doc.createElement('link'); link.rel = 'stylesheet'; link.href = '/fly/fly/bundles/cbsnewscontent/css/cmp-banner.min.css?v=50747257b890e014813016b79ece0fb2'; doc.head.appendChild(link); doc.body.innerHTML = CONSENT_MESSAGE; } else { el.insertAdjacentHTML('afterend', CONSENT_MESSAGE); } }); } function hidePrivacyMessage() { // Remove from the main document document.querySelectorAll(`.${CONSENT_MESSAGE_CLASS}`).forEach(el => el.remove()); // Remove from inside any iframes document.querySelectorAll('iframe').forEach(iframe => { const doc = iframe.contentDocument || iframe.contentWindow.document; doc.querySelectorAll(`.${CONSENT_MESSAGE_CLASS}`).forEach(el => el.remove()); }); } function activateGatedScripts() { // Handle both new format (cmp-gated-script) and old OneTrust/Ketch format (optanon-category-4) const gatedScripts = Array.from(document.querySelectorAll('script.cmp-gated-script, script.optanon-category-4')); // Activate scripts sequentially with a small delay to avoid timing issues let delay = 0; gatedScripts.forEach(function(placeholder, index) { setTimeout(function() { // Skip if already processed if (placeholder.hasAttribute('data-cmp-processed')) { return; } placeholder.setAttribute('data-cmp-processed', 'true'); const newScript = document.createElement('script'); newScript.type = 'text/javascript'; // Try new format first (data-cmp-src), then fall back to old format (data-src) const src = placeholder.getAttribute('data-cmp-src') || placeholder.getAttribute('data-src'); if (src) { newScript.src = src; } else if (placeholder.textContent) { // Inline script - just copy the content newScript.textContent = placeholder.textContent; } // Handle new format attributes (data-cmp-attrs) - for both inline and external scripts const attrs = placeholder.getAttribute('data-cmp-attrs'); if (attrs) { const tempDiv = document.createElement('div'); tempDiv.innerHTML = '
<\/div>'; const tempAttrs = tempDiv.firstChild.attributes; for (let i = 0; i < tempAttrs.length; i++) { // For external scripts, allow defer/async. For inline scripts, skip them (not valid) if (src || (tempAttrs[i].name !== 'async' && tempAttrs[i].name !== 'defer')) { newScript.setAttribute(tempAttrs[i].name, tempAttrs[i].value); } } } // Copy other attributes from old OneTrust format for (let i = 0; i < placeholder.attributes.length; i++) { const attr = placeholder.attributes[i]; // Skip attributes we've already handled or don't want to copy if (!['class', 'data-src', 'data-type', 'data-cmp-src', 'data-cmp-attrs', 'data-cmp-processed', 'type', 'async', 'defer', 'src'].includes(attr.name)) { newScript.setAttribute(attr.name, attr.value); } } placeholder.parentNode.replaceChild(newScript, placeholder); // If external script, manually trigger window.onload handlers after it loads // This handles widgets that use window.onload for initialization if (src) { newScript.addEventListener('load', function() { // If page already loaded and script set a new onload handler, trigger it if (document.readyState === 'complete' && window.onload) { const originalOnload = window.onload; window.onload = null; // Clear temporarily to prevent loops originalOnload(); // Execute the handler } }); } }, delay); delay += 500; // 500ms delay between each script to allow full loading }); } cbsoptanon.onScriptsReady(function(cmp) { cmp.ot.targetingAllowed(function(allowed) { if (!allowed) { showPrivacyMessage(); } else { activateGatedScripts(); } }); cmp.ot.awaitInitialConsent(function(consent_model) { cmp.ot.addOnConsentChangedHandler(function() { cmp.ot.targetingAllowed(function(allowed) { if (allowed) { hidePrivacyMessage(); activateGatedScripts(); } else { showPrivacyMessage(); } }); }); }); });