Marcado C2PA en las salidas de un generador de contenido
El requisito, en una frase
Si eres proveedor de un sistema de IA que genera texto, imagen, audio o vídeo, el artículo 50.2 te obliga a que esas salidas estén marcadas en un formato legible por máquina que permita detectar que son artificiales. No es una etiqueta visible para humanos (eso es el 50.4): es metadato o marca de agua que una máquina pueda leer. El estándar de referencia práctico lo fija el Código de Buenas Prácticas de la Comisión de junio de 2026, y la implementación dominante para imagen y vídeo es C2PA (Coalition for Content Provenance and Authenticity).
Qué te da ya la API (y qué no)
Lo primero que comprobamos al auditar nuestros propios generadores: qué parte del trabajo ya la hace el proveedor del modelo.
- Imagen (DALL·E, Imagen, Firefly…): algunos proveedores ya incrustan C2PA o SynthID en las imágenes que devuelven. Pero cuidado: si tu pipeline reprocesa la imagen (recorte, compresión, conversión a WebP), los metadatos se pierden y la responsabilidad de re-marcarla es tuya como proveedor del sistema.
- Texto (Claude, GPT…): la API te devuelve texto plano, sin marca alguna. El marcado de texto es técnicamente el más débil de todo el artículo 50.2 — el propio Código de Buenas Prácticas reconoce que para texto valen soluciones a nivel de sistema (metadatos en el documento contenedor, declaración en el HTML) más que marcas de agua lingüísticas.
- Audio/vídeo: depende del proveedor; en general, asume que el marcado es cosa tuya.
Conclusión operativa: no puedes delegar el 50.2 en la API. Tu sistema es el que se comercializa; tu sistema es el que tiene que marcar.
La arquitectura que usamos
En nuestro generador de contenido el flujo es: el usuario pide una pieza → el backend PHP llama al modelo → la salida pasa por un paso de firma antes de almacenarse o entregarse. Ese paso es un servicio pequeño y aburrido, y eso es lo que lo hace fiable: todo lo que sale del sistema pasa por ahí, sin excepciones por tipo de contenido.
Imágenes: manifiesto C2PA con c2patool
La herramienta de referencia es c2patool (CLI oficial del proyecto C2PA). Definimos un manifiesto que declara que la imagen fue generada por IA:
{
"claim_generator": "KraakWorks-ContentGen/1.0",
"assertions": [
{
"label": "c2pa.actions",
"data": {
"actions": [
{
"action": "c2pa.created",
"digitalSourceType": "http://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia"
}
]
}
}
]
}
Y el paso de firma en PHP invoca la herramienta sobre cada imagen generada:
<?php
final class C2paSigner
{
public function __construct(
private string $c2patool, // ruta al binario c2patool
private string $manifest, // ruta al manifiesto JSON
private string $certPath, // certificado de firma (ES256)
private string $keyPath,
) {}
/** Firma in-place. Lanza excepción si la imagen sale sin marcar. */
public function sign(string $imagePath): void
{
$out = $imagePath . '.signed';
$cmd = sprintf(
'%s %s -m %s -s %s -k %s -o %s 2>&1',
escapeshellcmd($this->c2patool),
escapeshellarg($imagePath),
escapeshellarg($this->manifest),
escapeshellarg($this->certPath),
escapeshellarg($this->keyPath),
escapeshellarg($out)
);
exec($cmd, $log, $code);
if ($code !== 0 || !is_file($out)) {
// Regla de la casa: si no se puede marcar, no se entrega.
throw new RuntimeException('C2PA signing failed: ' . implode("\n", $log));
}
rename($out, $imagePath);
}
}
El fallback barato: IPTC DigitalSourceType
C2PA exige gestionar certificados de firma. Mientras montas eso, hay un mínimo defendible e inmediato: el campo IPTC DigitalSourceType con el valor trainedAlgorithmicMedia, que es exactamente el vocabulario que usan Google y Meta para detectar contenido sintético. Con exiftool:
<?php
function markAsAiGenerated(string $imagePath): void
{
$cmd = sprintf(
'exiftool -overwrite_original ' .
'-XMP-iptcExt:DigitalSourceType=' .
'"http://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia" ' .
'-XMP-dc:Description="AI-generated content" %s 2>&1',
escapeshellarg($imagePath)
);
exec($cmd, $log, $code);
if ($code !== 0) {
throw new RuntimeException('IPTC marking failed: ' . implode("\n", $log));
}
}
No es equivalente a C2PA (no hay firma criptográfica, cualquiera puede borrar el metadato), pero es marcado legible por máquina, interoperable y documentable. Nuestra recomendación: IPTC hoy, C2PA como objetivo, y las dos cosas escritas en tu documentación técnica con fecha.
Texto: declaración a nivel de sistema
Para texto generado que se publica vía web hacemos dos cosas: metadato en el HTML y cabecera en los ficheros exportados.
<!-- En la página que muestra contenido generado -->
<meta name="generator" content="ai-generated">
<article data-ai-generated="true" data-generator="KraakWorks-ContentGen/1.0">
…
</article>
Qué guardar para una inspección
| Evidencia | Dónde |
|---|---|
| Decisión técnica de marcado (qué estándar, por qué, desde cuándo) | Documentación técnica del sistema |
| Log de firmas por salida (id, timestamp, resultado) | Base de datos / logs retenidos |
| Muestreo periódico de salidas verificando la marca | Tarea programada + informe mensual |
| Tratamiento de errores: qué pasa cuando la firma falla | Este mismo código — la excepción es la evidencia |
¿Lo implementamos en tu generador?
Implementación de transparencia: marcado técnico de salidas, por sistema, con precio cerrado. Escríbenos y te decimos en una llamada qué pieza te falta.