diff --git a/backend/tests/Taskdeck.Api.Tests/RawJsonAdversarialApiTests.cs b/backend/tests/Taskdeck.Api.Tests/RawJsonAdversarialApiTests.cs
new file mode 100644
index 00000000..1ca57c14
--- /dev/null
+++ b/backend/tests/Taskdeck.Api.Tests/RawJsonAdversarialApiTests.cs
@@ -0,0 +1,362 @@
+using System.Net;
+using System.Net.Http.Json;
+using System.Text;
+using FluentAssertions;
+using Taskdeck.Api.Tests.Support;
+using Taskdeck.Application.DTOs;
+using Xunit;
+
+namespace Taskdeck.Api.Tests;
+
+///
+/// Adversarial tests that send raw JSON to API endpoints to exercise edge cases
+/// that typed DTO serialization cannot reach: floating-point positions, integer overflow,
+/// type mismatches, duplicate board names, and card description boundary values.
+/// Key property: NO 500 Internal Server Error from any malformed input.
+///
+public class RawJsonAdversarialApiTests : IClassFixture
+{
+ private readonly TestWebApplicationFactory _factory;
+ private readonly HttpClient _client;
+ private bool _isAuthenticated;
+
+ public RawJsonAdversarialApiTests(TestWebApplicationFactory factory)
+ {
+ _factory = factory;
+ _client = factory.CreateClient();
+ }
+
+ private async Task EnsureAuthenticatedAsync()
+ {
+ if (_isAuthenticated) return;
+ await ApiTestHarness.AuthenticateAsync(_client, "raw-json-adversarial");
+ _isAuthenticated = true;
+ }
+
+ // ─────────────────────── Card position as float/string/boundary via raw JSON ───────────────────────
+
+ [Theory]
+ [InlineData("{\"boardId\": \"BOARD_ID\", \"columnId\": \"COL_ID\", \"title\": \"test\", \"position\": 3.14}")]
+ [InlineData("{\"boardId\": \"BOARD_ID\", \"columnId\": \"COL_ID\", \"title\": \"test\", \"position\": -1}")]
+ [InlineData("{\"boardId\": \"BOARD_ID\", \"columnId\": \"COL_ID\", \"title\": \"test\", \"position\": 2147483647}")]
+ [InlineData("{\"boardId\": \"BOARD_ID\", \"columnId\": \"COL_ID\", \"title\": \"test\", \"position\": -2147483648}")]
+ [InlineData("{\"boardId\": \"BOARD_ID\", \"columnId\": \"COL_ID\", \"title\": \"test\", \"position\": 9999999999999}")]
+ [InlineData("{\"boardId\": \"BOARD_ID\", \"columnId\": \"COL_ID\", \"title\": \"test\", \"position\": \"not-a-number\"}")]
+ [InlineData("{\"boardId\": \"BOARD_ID\", \"columnId\": \"COL_ID\", \"title\": \"test\", \"position\": null}")]
+ [InlineData("{\"boardId\": \"BOARD_ID\", \"columnId\": \"COL_ID\", \"title\": \"test\", \"position\": true}")]
+ [InlineData("{\"boardId\": \"BOARD_ID\", \"columnId\": \"COL_ID\", \"title\": \"test\", \"position\": [1,2,3]}")]
+ public async Task CreateCard_WithAdversarialPosition_NeverReturns500(string bodyTemplate)
+ {
+ await EnsureAuthenticatedAsync();
+
+ // Create board and column
+ var boardResponse = await _client.PostAsJsonAsync("/api/boards",
+ new CreateBoardDto($"pos-test-{Guid.NewGuid():N}", null));
+ boardResponse.StatusCode.Should().Be(HttpStatusCode.Created);
+ var board = await boardResponse.Content.ReadFromJsonAsync();
+
+ var colResponse = await _client.PostAsJsonAsync(
+ $"/api/boards/{board!.Id}/columns",
+ new CreateColumnDto(board.Id, "TestCol", null, null));
+ colResponse.StatusCode.Should().Be(HttpStatusCode.Created);
+ var col = await colResponse.Content.ReadFromJsonAsync();
+
+ // Substitute actual IDs into the raw JSON
+ var body = bodyTemplate
+ .Replace("BOARD_ID", board.Id.ToString())
+ .Replace("COL_ID", col!.Id.ToString());
+
+ var content = new StringContent(body, Encoding.UTF8, "application/json");
+ var response = await _client.PostAsync($"/api/boards/{board.Id}/cards", content);
+
+ ((int)response.StatusCode).Should().BeLessThan(500,
+ $"Card creation returned 500 for position edge case: {bodyTemplate}");
+ }
+
+ // ─────────────────────── Card description adversarial content via API ───────────────────────
+
+ [Theory]
+ [InlineData("")]
+ [InlineData("\u0000\u0001\u0002\u0003")]
+ [InlineData("")]
+ [InlineData("
")]
+ [InlineData("