)]}'
{
  "log": [
    {
      "commit": "3fedac02917fd2422ac5d7a454d6abafcc00fe53",
      "tree": "b626332abce6fb7d1b66295a81822ae0eb6e2fab",
      "parents": [
        "d877250b6321f439538bc651e24b1e86bb76f140"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Fri Aug 21 23:21:48 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Fri Aug 21 23:21:48 2026 +0200"
      },
      "message": "add changelog hint to announce mail\n"
    },
    {
      "commit": "d877250b6321f439538bc651e24b1e86bb76f140",
      "tree": "4dbddf0f030a6f48b3644f8e393282e914c966da",
      "parents": [
        "9e28a9cf938fa7c0ed38d3a8ac0ed90eb99e452f"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Fri Aug 21 23:00:23 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Fri Aug 21 23:00:23 2026 +0200"
      },
      "message": "update 3.4.0 release date\n"
    },
    {
      "commit": "9e28a9cf938fa7c0ed38d3a8ac0ed90eb99e452f",
      "tree": "bcdf6f9faee6311a15075f3c76b93f34989f2530",
      "parents": [
        "8bb9233846abd7605cb365f4f75b05afd385b00c"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Thu Aug 20 21:14:52 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Thu Aug 20 21:14:52 2026 +0200"
      },
      "message": "bump version to 3.4.1\n"
    },
    {
      "commit": "8bb9233846abd7605cb365f4f75b05afd385b00c",
      "tree": "02837123bf626e22fc332c25877814728d281e55",
      "parents": [
        "556741f71a7e900edff30e59fdc8de201ebda574",
        "36aa1edc6b8f47428817539c4ca0b1b3324cdbb8"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "43271715+FreeAndNil@users.noreply.github.com",
        "time": "Thu Aug 20 07:45:37 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Aug 20 07:45:37 2026 +0200"
      },
      "message": "Recognise a native host as having no configuration system (#162)\n\nFixes #162\n\nIn a process that hosts the runtime natively there is no entry assembly for the\nconfiguration system to derive the config file path from, so reading an\napplication setting fails in ClientConfigPaths with a PlatformNotSupportedException\nwrapped in a ConfigurationErrorsException. That matched none of the shapes\nIsMissingConfigurationSystem recognised, so log4net blamed the user\u0027s config file\nand repeated the report for every setting the static constructors read: seven\nlog4net:ERROR blocks with a stack trace each, at startup, in a well configured\napplication.\n\nA PlatformNotSupportedException anywhere in the inner exception chain is now\ntreated as an absent configuration system, the same as the Native AOT case. A\nmalformed config file cannot produce one, so unlike the FileNotFoundException and\nTypeLoadException cases it needs no check on which assembly it came from. The\nfailure is logged once at debug level and application settings come from\nenvironment variables.\n\nVerified on Windows in a C++ host of the CoreCLR built for the purpose, in a host\nthat loads the runtime through hostfxr, and in powershell.exe loading a\nnetstandard2.0 build output: seven error blocks before, none after, and exactly one\ndebug line with log4net.Internal.Debug on."
    },
    {
      "commit": "556741f71a7e900edff30e59fdc8de201ebda574",
      "tree": "6f631efbf843255e25d83a6d462e5a376f58529e",
      "parents": [
        "861c533ad8259146ea1837f4a20e9d75ed40829d"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 19 23:10:45 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 19 23:10:45 2026 +0200"
      },
      "message": "wrapping lines\n"
    },
    {
      "commit": "861c533ad8259146ea1837f4a20e9d75ed40829d",
      "tree": "393a209e34ed69510877bf0dc6de510c65017422",
      "parents": [
        "b710fdd32ad0f840a4983cfb05bcd4f3330358f7"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 19 23:09:27 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 19 23:09:27 2026 +0200"
      },
      "message": "fix typo\n"
    },
    {
      "commit": "36aa1edc6b8f47428817539c4ca0b1b3324cdbb8",
      "tree": "2229c9540839373bc9cff9333d25368809fddec4",
      "parents": [
        "24457a61a1597541595a1b374af7c3daa61dd752"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 19 22:42:56 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 19 22:56:32 2026 +0200"
      },
      "message": "Document the pattern layout tests\n\nEvery test method, the fixture hooks and the layout factories now carry a\nsummary saying what they assert, as does the converter that feeds arbitrary\nnames to NamedPatternConverter. The factories note that\nDynamicPatternLayoutTest inherits this fixture and reruns the whole suite\nagainst a DynamicPatternLayout, which is not obvious from either file.\n\nThe conditional using directive that came with it keeps System.Linq out of the\nnet462 compilation, where nothing uses it, which clears an IDE0005 warning.\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "24457a61a1597541595a1b374af7c3daa61dd752",
      "tree": "5b91f9a80a21827b003d28f94252ba930c75cf9c",
      "parents": [
        "13d931ef36ecc607786befc4c4cee2226a52ffc8"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 19 22:42:48 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 19 22:44:25 2026 +0200"
      },
      "message": "Guard the native host case in CI (#162)\n\nThe unit test for a natively hosted process builds the exception by hand, so it\nasserts what we believe the configuration system does rather than what it does.\nThis adds a check that removes the entry assembly for real and reports what\nlog4net writes while starting up, in the project that already exists to record\nwhat log4net can do in an unusual host.\n\nIt cannot be one of the probes in the list: the configuration system caches its\ninitialization and log4net reads its first application setting from a static\nconstructor, so by the time any probe runs the outcome is already decided. The\ncheck therefore owns the process from its first statement and the runner selects\nit with an argument.\n\nVerified in both directions: it passes as committed, and reverting the\nPlatformNotSupportedException case makes it exit non-zero and print the seven\nerror blocks it captured.\n\nJIT compiled only, deliberately. Native AOT trims the configuration system away,\nso the first setting read there fails as a missing constructor long before it can\nfail for want of an entry assembly: the published executable passes this check\neven with the fix reverted, which would be a green that cannot fail for the\nreason the check exists. The reason is recorded next to the CI step and on the\nclass, so it does not get added back for symmetry.\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "13d931ef36ecc607786befc4c4cee2226a52ffc8",
      "tree": "58358f4b94701fc32345586086c68034b645e511",
      "parents": [
        "b710fdd32ad0f840a4983cfb05bcd4f3330358f7"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 19 22:12:52 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 19 22:44:24 2026 +0200"
      },
      "message": "Recognise a native host as having no configuration system (#162)\n\nIn a process that hosts the runtime natively there is no entry assembly for the\nconfiguration system to derive the config file path from, so reading an\napplication setting fails in ClientConfigPaths with a PlatformNotSupportedException\nwrapped in a ConfigurationErrorsException. That matched none of the shapes\nIsMissingConfigurationSystem recognised, so log4net blamed the user\u0027s config file\nand repeated the report for every setting the static constructors read: seven\nlog4net:ERROR blocks with a stack trace each, at startup, in a well configured\napplication.\n\nA PlatformNotSupportedException anywhere in the inner exception chain is now\ntreated as an absent configuration system, the same as the Native AOT case. A\nmalformed config file cannot produce one, so unlike the FileNotFoundException and\nTypeLoadException cases it needs no check on which assembly it came from. The\nfailure is logged once at debug level and application settings come from\nenvironment variables.\n\nVerified on Windows in a C++ host of the CoreCLR built for the purpose, in a host\nthat loads the runtime through hostfxr, and in powershell.exe loading a\nnetstandard2.0 build output: seven error blocks before, none after, and exactly one\ndebug line with log4net.Internal.Debug on.\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "b710fdd32ad0f840a4983cfb05bcd4f3330358f7",
      "tree": "2cde985be278e0c0ab2a4fec3b62ccfa0d72379a",
      "parents": [
        "44781ede2b9c66bc10485b013bbf0c4aa39202a4"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 19 22:43:43 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 19 22:43:43 2026 +0200"
      },
      "message": "graphify update\n"
    },
    {
      "commit": "44781ede2b9c66bc10485b013bbf0c4aa39202a4",
      "tree": "9c03ce63bc2d35b975bf36a7637954441b681ebe",
      "parents": [
        "11d79673925a8f1afacbc1f2a8f3bcb1f91c0771"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 19 22:11:56 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 19 22:11:56 2026 +0200"
      },
      "message": "add fixed by hint\n"
    },
    {
      "commit": "11d79673925a8f1afacbc1f2a8f3bcb1f91c0771",
      "tree": "04d490c0fc69add838103c14bc1009e4fa8eccf8",
      "parents": [
        "cb808518af941f7adcb0302bdf855a2c8ab405bf"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 19 22:06:50 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 19 22:06:50 2026 +0200"
      },
      "message": "graphify update\n"
    },
    {
      "commit": "cb808518af941f7adcb0302bdf855a2c8ab405bf",
      "tree": "e8f595809661ec50cb0e071fb316ab45190a09b1",
      "parents": [
        "71c038c1860b331ca944840702d72da53e4cb41f"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 23:37:26 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 23:37:26 2026 +0200"
      },
      "message": "fix the release verification instructions for Linux\n\nverify-release.sh runs in a child process, so the \"cd src\" appended to it in 71631474 never reached the reviewer\u0027s shell and left them one level above the Dockerfile, breaking the docker build step. Move the step back into release-review.adoc and align the manual extract block with it.\n"
    },
    {
      "commit": "71c038c1860b331ca944840702d72da53e4cb41f",
      "tree": "c3c7f972db98b3e588d8aefcc9288abbfd9a8b4a",
      "parents": [
        "e3246a54283e2785243dd83913c25cea93eb31eb",
        "843ccfc1fcb9f263e1e8fb164cf550bd155a2f42"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "43271715+FreeAndNil@users.noreply.github.com",
        "time": "Tue Aug 18 15:03:45 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Aug 18 15:03:45 2026 +0200"
      },
      "message": "Harden log4net against the findings of a security audit\n\nAppenders: network and transport\n\n- 2fb4539f time out writes to stalled TelnetAppender clients\n- 15d16eed add a listen address to TelnetAppender\n- bd35fe0d add a TransportSecurity option to the MailKit SmtpAppender\n\nAppenders: syslog record integrity\n\n- eccb876e escape NUL characters in LocalSyslogAppender messages\n- 46582e52 report a RemoteSyslogAppender Identity that would split the record\n- 360a1026 fix the lifetime of the LocalSyslogAppender identity\n\nAdoNet appender\n\n- 9f5c9557 contain per-event failures in AdoNetAppender.SendBuffer\n- 19fdb4a2 warn when AdoNetAppender executes layout-generated SQL\n- e80b3810 redact the password when reporting a failed database connection\n\nReliability and resource bounds\n\n- 3fd97cb5 bound the waits for the file locking mutexes\n- 394fd3dc bound regular expression matching in the string match filters\n- 86ecb152 flush TextWriterAppender under the appender lock\n- 1786b139 keep the impersonated user name when a logging event is fixed\n\nDiagnostics\n\n- ecd1b8b9 report the first appender error without log4net.Internal.Debug\n\nBuild and release infrastructure\n\n- 9cc34d29 make the release verification scripts fail closed\n- 28d411a5 pin the Maven wrapper and distribution downloads\n- e203b7c7 remove the git-broadcast workflow\n\nDocumentation\n\n- 6bc3df34 document that configuration is trusted input\n- 287fa9cd document that format strings are trusted developer input\n- dc17e1ba document the conventions the security scan work relied on (#309)\n\nNotes for reviewers\n\nSeveral commits introduce secure defaults with a named opt-out (SendTimeoutMillis, MatchTimeoutMillis, LockTimeoutMillis); those are behaviour changes on upgrade and are recorded in the changelog. The documentation commits deliberately settle recurring reports in the threat model rather than changing code."
    },
    {
      "commit": "843ccfc1fcb9f263e1e8fb164cf550bd155a2f42",
      "tree": "c3c7f972db98b3e588d8aefcc9288abbfd9a8b4a",
      "parents": [
        "1c664f85b688006e6259eaf6f32e261ecdba979f"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 11:20:56 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 11:20:56 2026 +0200"
      },
      "message": "fix AcquireLockGivesUpWhenTheLockIsHeldTooLong on Windows #310\n"
    },
    {
      "commit": "1c664f85b688006e6259eaf6f32e261ecdba979f",
      "tree": "4e2206b3ebb5c9e2b950db8849d4735b6885e5c2",
      "parents": [
        "dc17e1ba381460a6fd0eb0ac0660922e89350e7a"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 10:43:13 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 10:43:13 2026 +0200"
      },
      "message": "New PR number (#310)\n"
    },
    {
      "commit": "e3246a54283e2785243dd83913c25cea93eb31eb",
      "tree": "757f0efc0823e827b9258122c94a2f5efe17b379",
      "parents": [
        "1acfaa6a3e09770e22cc1b57f5902fda06bbfadc",
        "cf8aa32adbdd417b8982af579cb619781b2be92c"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "43271715+FreeAndNil@users.noreply.github.com",
        "time": "Tue Aug 18 10:30:55 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Aug 18 10:30:55 2026 +0200"
      },
      "message": "Merge pull request #306 from apache/Feature/306-aot-calling-assembly\n\nmake log4net usable from a PublishAOT build (#306)"
    },
    {
      "commit": "dc17e1ba381460a6fd0eb0ac0660922e89350e7a",
      "tree": "c0f6a54394d8bdd63f4f0ab8d166a21571cd22d0",
      "parents": [
        "e203b7c7424496595b004e0ae62147bc3f43fde0"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 00:49:40 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 00:49:40 2026 +0200"
      },
      "message": "document the conventions the security scan work relied on #309\n"
    },
    {
      "commit": "e203b7c7424496595b004e0ae62147bc3f43fde0",
      "tree": "f435db73e1f1af187ecad6046d6d39ab0e4246aa",
      "parents": [
        "28d411a53b7f61b0da7f9324181e6a23f926cd39"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 00:02:45 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 00:09:22 2026 +0200"
      },
      "message": "remove the git-broadcast workflow\n\nIts push and pull request triggers had been commented out, leaving it\ndispatched by hand only, so nothing depends on it.\n\nWhat remained was worth removing rather than pinning: it ran\nnpx git-broadcast@beta in a job that checks out with a token able to push to\nthis repository, using mutable action tags and with no permissions block.\nThe beta dist-tag resolves to 0.45.7 from 2024, older than the 0.50.0 that\nlatest points at, so it was not tracking newer code either; it was simply a\npointer that can be moved to any published version.\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "28d411a53b7f61b0da7f9324181e6a23f926cd39",
      "tree": "c60a351079d2e946d157ff3ccd6c4513506d257e",
      "parents": [
        "15d16eedf5804c5b441db52096d4ee018a4e5028"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 00:02:34 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 00:09:22 2026 +0200"
      },
      "message": "pin the Maven wrapper and distribution downloads\n\nmvnw and MavenWrapperDownloader both refuse to run when a download does not\nmatch a checksum, but neither wrapperSha256Sum nor distributionSha256Sum was\nset, so the enforcement never ran and whatever the URLs returned was\nexecuted.\n\nwrapperSha256Sum is of the maven-wrapper.jar committed next to the\nproperties, which is byte identical to the published maven-wrapper-3.2.0.jar.\n\ndistributionSha256Sum is of apache-maven-3.9.0-bin.zip from\narchive.apache.org, whose SHA-512 matches the published value, which is byte\nidentical to the copy on Maven Central, and whose PGP signature verifies\nagainst https://downloads.apache.org/maven/KEYS.\n\nBoth enforcement paths were exercised: with the checksums correct mvnw runs\nMaven 3.9.0, and with either one altered it refuses.\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "15d16eedf5804c5b441db52096d4ee018a4e5028",
      "tree": "c44d0dffe1021de956d100bdf8dfc30d624f4c39",
      "parents": [
        "3fd97cb511b2a99b3b4b6957ea606a2e5a6ab804"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Aug 17 23:56:00 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 00:09:21 2026 +0200"
      },
      "message": "add a listen address to TelnetAppender\n\nThe listening socket was bound to IPAddress.Any with no way to scope it, so\nan operator who only wanted to watch the log from the machine itself still\ngot a listener on every interface.\n\nListenAddress fills that gap. The default is unchanged, so nothing moves\nunless it is set: the connecting client is trusted, as the manual now\nstates, and flipping the default would break every remote monitoring setup\non upgrade.\n\nThe listening socket now takes its family from the address rather than\nalways being InterNetwork, so an IPv6 address works too.\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "3fd97cb511b2a99b3b4b6957ea606a2e5a6ab804",
      "tree": "8b264e59a9e1af31a2735cebde5806dbe07e75e8",
      "parents": [
        "360a10268bc6e977a3b8e5c3db9231b33aed7562"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Aug 17 23:52:21 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 00:09:21 2026 +0200"
      },
      "message": "bound the waits for the file locking mutexes\n\nInterProcessLock.AcquireLock carried a \"TODO: add timeout?\" and waited\nwithout one, as did RollingFileAppender when deciding whether to roll. Both\nwaits happen while the appender lock is held, so a mutex nobody releases\nsuspended every thread logging through the appender.\n\nBoth now wait at most LockTimeoutMillis, 10000 by default, with\nTimeout.Infinite restoring the previous behaviour. An event that cannot get\nthe file lock is reported and dropped; one that cannot get the rolling lock\nis written to the current file without the roll check, because rolling\nwithout the lock would race another process renaming the same files.\n\nTwo more problems turned up on the way:\n\nAbandonedMutexException was unhandled although it means the wait succeeded\nand this thread owns the mutex. It propagated out of AcquireLock before\n_recursiveWatch was incremented, so ReleaseLock never released it and the\nmutex stayed held for good. That needs no attacker, only a process dying\nmid-write.\n\nAdjustFileBeforeAppend released the rolling mutex in a finally without\nchecking that it had been taken. Harmless while the wait could only succeed,\nbut a bounded wait makes it throw, so it is guarded now.\n\nThe mutex names are left alone. They are derived from the log file path so\nthat separate processes agree on them, and making them unpredictable would\nbreak the cross-process coordination they exist for.\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "360a10268bc6e977a3b8e5c3db9231b33aed7562",
      "tree": "54762a7c2295f3a91a2e4aafceedcdd22470730f",
      "parents": [
        "9cc34d29e31b985e8e7d028220d9235c83fc9c7a"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Aug 17 23:39:09 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 00:09:20 2026 +0200"
      },
      "message": "fix the lifetime of the LocalSyslogAppender identity\n\nopenlog keeps the pointer it is given rather than a copy of the string, and\nregisters it for the process rather than for an appender.\n\nActivateOptions allocated a new buffer and overwrote the handle to the\nprevious one without freeing it, so every re-activation leaked a buffer. The\nhandle is now replaced under a lock, and the old buffer is freed only once\nopenlog points at the new string. A failing openlog frees the new one.\n\nThe handle became static, which is what the registration already was: a\nsecond appender replaces the identity of the first rather than adding one.\n\nOnClose no longer frees it. The buffer belongs to a process wide\nregistration that outlives the appender, and another instance may still be\nlogging through it. That closelog ends the connection for every instance is\nnow documented as well.\n\nThe use-after-free the audit describes does not apply to the libcs log4net\ntargets: closelog runs before the free and glibc clears its stored pointer,\nwhile musl copies the ident. Only the leak and the shared lifetime are\nfixed here.\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "9cc34d29e31b985e8e7d028220d9235c83fc9c7a",
      "tree": "82e39fcbf873f19aec31784bb9a477142c65675c",
      "parents": [
        "287fa9cd044f15bf8ccd5ef8e04caa748e91fb59"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Aug 17 23:30:16 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 00:09:20 2026 +0200"
      },
      "message": "make the release verification scripts fail closed\n\nverify-release.ps1 reported a SHA-512 mismatch with -ErrorAction Continue,\nwhich overrides the script level $ErrorActionPreference, and never checked\nthe exit code of gpg, because $ErrorActionPreference does not apply to\nnative commands. A tampered artifact or a broken signature therefore still\nreached Expand-Archive and the script exited 0. build-release.ps1 already\nsets $PSNativeCommandUseErrorActionPreference with a comment explaining\nthis, so the trap was known.\n\nBoth scripts looped over whichever .asc files happened to be present, so\ndeleting them left nothing to verify and the scripts succeeded. The .sha512\nfiles travel with the artifacts and can be regenerated, so they add nothing\non their own.\n\nVerification is now driven from the artifacts: everything that is not a\nhash, a signature or KEYS must have both, and an empty directory is an\nerror. That also catches a file added to the release.\n\nBoth scripts now import KEYS into a key ring of their own. Importing into\nthe default one accepted a signature from any key the machine already\ntrusted rather than only from a key in the Logging Services KEYS file.\n\nChecked against a synthetic release signed with a throwaway key. Before,\nthe PowerShell script accepted a tampered artifact, a corrupted signature,\na deleted signature, an added unsigned file and a signature from an\nuntrusted key, and the shell script accepted the last three. After, all of\nthem are rejected and an untampered release still passes.\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "287fa9cd044f15bf8ccd5ef8e04caa748e91fb59",
      "tree": "f29999b1f5645c70c2cceec391a7737d90d5a442",
      "parents": [
        "1786b139aad01148120f981cba80336c2c505f6e"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Aug 17 23:16:27 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 00:09:19 2026 +0200"
      },
      "message": "document that format strings are trusted developer input\n\nComposite formatting honours the alignment of a format item before anything\ncan reject it, so a format such as \"{0,2000000000}\" allocates a buffer of\nthat size, and the OutOfMemoryException is fatal and escapes the catch that\notherwise turns a bad format into an error string. Security scans report\nthis, so record why it is not guarded against, with a link to the threat\nmodel.\n\nFormat strings are developer-controlled and trusted, and routing user data\ninto one is application misuse.\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "1786b139aad01148120f981cba80336c2c505f6e",
      "tree": "d952b074bf052a7bc5901f606e8c8f18130189f5",
      "parents": [
        "86ecb1526ff9fbdb94b823a27f4e8f49cf250952"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Aug 17 23:06:40 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 00:09:19 2026 +0200"
      },
      "message": "keep the impersonated user name when a logging event is fixed\n\nUserName resolved the identity of whichever thread read it, so with a\nbuffering appender the buffered events were attributed to the thread\nflushing the buffer rather than the one that logged them.\n\nOnly impersonation makes that wrong. Without it the name is the process\nidentity, which is the same on every thread and stays resolvable, so it is\nstill resolved lazily and nothing changes for those applications.\n\nAn event logged while impersonating now takes its user name with it when it\nis fixed, because that is the last point at which the identity is known.\nThis happens whatever Fix asks for, and outside the block that fixes the\nrequested fields, since that block is skipped when there is nothing to fix\nwhile the cache is locked all the same. FixFlags.UserName stays unset, so\nthe flags keep reporting what the caller requested.\n\nReading the property on a thread that is impersonating no longer reports\nthat thread\u0027s user; the not available text is used instead.\n\nThe impersonation check only queries the thread token. Resolving the name\nbehind it is the expensive part and is unchanged.\n\nAlso renames FixingTest.All_ShouldContainAllFlags and documents its members.\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "86ecb1526ff9fbdb94b823a27f4e8f49cf250952",
      "tree": "2c5e0cb4ecd8513021e4a94ccd39e6fe4e6368e0",
      "parents": [
        "394fd3dc8316de38bf013b23b86fa07fbfdf0e71"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Aug 17 22:50:58 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 00:09:18 2026 +0200"
      },
      "message": "flush TextWriterAppender under the appender lock\n\nFlush synchronized on a private object while Append runs under the lock\ntaken by DoAppend, so a flush could run concurrently with a write to the\nsame QuietTextWriter, which is not thread safe. The comment claiming the\nlock blocked any Append was left over from when it locked on this.\n\nAll four lock sites in the class now take the inherited LockObj and the\nprivate object is gone, so no ordering between two locks remains. Taking\nLockObj in OnClose is safe because Close already holds it and Monitor is\nreentrant.\n\nFlush also returned true whatever happened. QuietTextWriter routes failing\nwrites to the ErrorHandler but does not override Flush, so a failure from\nthe underlying writer escaped to the caller. It is now reported with\nErrorCode.FlushFailure and Flush returns false.\n\nThe AdoNet test doubles gained the doc comments the rest of the test code\nhas, matching Log4NetTransaction.\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "394fd3dc8316de38bf013b23b86fa07fbfdf0e71",
      "tree": "7fd2169010e0be57cc92b70bbf9fdb389e2bc924",
      "parents": [
        "46582e5204e004bf26569242597acd8896752919"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Aug 17 22:41:45 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 00:09:17 2026 +0200"
      },
      "message": "bound regular expression matching in the string match filters\n\nRegexToMatch was compiled with Regex.InfiniteMatchTimeout, and the match\nruns while the appender lock is held, so a pattern that backtracks could\nstall everything logging through the appender on some inputs.\n\nMatching now stops after MatchTimeoutMillis, 1000 by default, and 0 restores\nthe previous unbounded behaviour. An abandoned match counts as no match, so\nthe event is left to the rest of the filter chain rather than having its\ndecision changed.\n\nThe pattern comes from configuration and is trusted, so this is hardening\nagainst a pattern that turns out to be expensive, not protection against\nuntrusted input.\n\nStringMatchFilter and PropertyFilter both matched the regex themselves, so\nthe handling lives in one protected IsRegexMatch used by both, which also\ncovers MdcFilter and NdcFilter. It reports an abandoned match once per\nfilter rather than once per event, since a warning per event would be a\nproblem of its own.\n\nregexToMatch was missing from the manual entirely and is documented now.\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "46582e5204e004bf26569242597acd8896752919",
      "tree": "a82b5d2c77b9cbd5df9d9fd97fdd087cdb3d73f7",
      "parents": [
        "eccb876ea4c07c3f3080835b7141b71077b12321"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Aug 17 22:30:49 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 00:09:17 2026 +0200"
      },
      "message": "report a RemoteSyslogAppender Identity that would split the record\n\nThe Identity becomes the TAG of the syslog record and was appended\nverbatim, two lines before the message part goes through AppendMessage\u0027s\nfiltering. A carriage return or line feed in the TAG ends the record, so the\ntext after it is read as a record of its own with its own facility and\nseverity.\n\nThe TAG is a structural identifier and is expected to be a constant rather\nthan a pattern rendering event data, so a malformed one is a configuration\nerror. It is now reported through the ErrorHandler instead of being repaired\nquietly.\n\nThe control characters are removed rather than the event being dropped. An\nIdentity pattern that does render event data would otherwise give control\nover whether a record survives at all.\n\nOnly control characters are removed. Identity defaults to the application\nfriendly name, which may contain a space, and a space cannot split the\nrecord.\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "eccb876ea4c07c3f3080835b7141b71077b12321",
      "tree": "82b1c020df5983d9145958f9aff70650ad954e93",
      "parents": [
        "bd35fe0d5d9d83150fed88e63fb7eb4e887174ea"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Aug 17 22:23:24 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 00:09:16 2026 +0200"
      },
      "message": "escape NUL characters in LocalSyslogAppender messages\n\nThe rendered message is marshaled to libc as a null-terminated string, so a\nNUL character anywhere in it ended the record there and silently dropped\neverything the layout rendered after it, including trailing fields and\nexception text. Logged content is not trusted and a NUL in it is an\nin-scope input, so an attacker who gets one logged could hide the tail of\nevery record.\n\nConfirmed with the same marshalling the appender uses: for a 24 character\nmessage with a NUL in the middle, libc sees 13 characters.\n\nNUL is now escaped as \\0. Other control characters are still passed\nthrough, because syslog(3) encodes them itself and newlines are needed for\nthe multi-line output an exception layout produces. RemoteSyslogAppender\ndrops unprintable characters instead, which would lose the stack traces\nthis appender is expected to carry.\n\nAlso switches the single statement tests added for the send timeout to\nexpression bodies.\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "bd35fe0d5d9d83150fed88e63fb7eb4e887174ea",
      "tree": "3a1b24464bcb014f95457d3192f499ab4128434e",
      "parents": [
        "6bc3df34ba304ec9db6f7c361bf3c1c7279af2eb"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Aug 17 22:15:15 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 00:09:16 2026 +0200"
      },
      "message": "add a TransportSecurity option to the MailKit SmtpAppender\n\nEnableSsl mapped to MailKit\u0027s SecureSocketOptions.Auto, which is\nopportunistic on every port other than 465. An attacker able to strip\nSTARTTLS from the EHLO response silently downgraded the session to\nplaintext, taking the credentials passed to Authenticate and the log\ncontent with it, while the operator had asked for an encrypted connection.\n\nEnableSsl now requires transport security: implicit TLS on port 465 and\nmandatory STARTTLS elsewhere, so connecting fails when the server offers no\nTLS, as System.Net.Mail.SmtpClient.EnableSsl does. The appender ships for\nthe first time in this release, so no configuration changes behaviour.\n\nOpportunistic STARTTLS is still reachable, but only by asking for it. The\nnew TransportSecurity option carries the full set of modes and EnableSsl\nbecame a shorthand for it, so the two cannot disagree. TransportSecurity\nalso covers a server expecting implicit TLS on a port other than 465, which\nneither Auto nor the legacy appender could reach.\n\nThe option uses its own enum rather than MailKit\u0027s SecureSocketOptions,\nwhich is not CLS compliant and would have needed CLSCompliant(false) on the\nprimary TLS setting.\n\nThe remarks on EnableSsl offered a custom ISmtpTransport for finer control,\nwhich no caller can supply because both the interface and the constructor\ntaking it are internal. Removed, since TransportSecurity is the answer now.\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "6bc3df34ba304ec9db6f7c361bf3c1c7279af2eb",
      "tree": "80c9f5dd9f394505e5c1390332a921f1e2bcdf63",
      "parents": [
        "e80b3810acb3a2c9cb9788dab1ef1b9e4aedcf42"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Aug 17 21:54:28 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 00:09:15 2026 +0200"
      },
      "message": "document that configuration is trusted input\n\nSecurity scans regularly report the configuration paths as cleartext\ntransport, credential exposure, unrestricted type loading and unverified\nreload. None of them is a vulnerability, so record why, with a link to the\nthreat model, at the places a scan actually flags:\n\n- InternalConfigure(ILoggerRepository, Uri) neither restricts the URI scheme\n  nor withholds the process credentials. The endpoint is named by the\n  configuration and is trusted for the same reason an appender destination\n  is; transmitting configuration confidentially is a deployer\n  responsibility. Nothing runs until an operator supplies a URI, either by\n  calling Configure(Uri) or through the log4net.Config appSetting.\n- ParseAppender instantiates the types the configuration names, and\n  SetParameter reaches non-public members, both by design.\n- ConfigureAndWatchHandler reloads a replaced file without re-checking its\n  origin; keeping the watched file writable only by the operator is a\n  deployer responsibility.\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "e80b3810acb3a2c9cb9788dab1ef1b9e4aedcf42",
      "tree": "d1b5aa3c4ab41e7cfbd3d6208ac600b1e12a76ca",
      "parents": [
        "2fb4539f5c78f7037061265346f3992f54bcad67"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Aug 17 21:54:18 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 00:09:15 2026 +0200"
      },
      "message": "redact the password when reporting a failed database connection\n\nInitializeDatabaseConnection named the resolved connection string in full\nwhen it could not open the connection, and the documented examples embed\nPassword\u003d... The message goes through the ErrorHandler, so it is what an\noperator sees while diagnosing exactly this failure.\n\nPassword-bearing keywords are now replaced with *****. The rest of the\nconnection string is kept, so the message stays useful for spotting a typo\nin the server name or catalog. If the string cannot be parsed - likely,\ngiven that it just failed to connect - all of it is redacted.\n\nThis matters more since appender errors became visible without\nlog4net.Internal.Debug: the password would otherwise have reached stderr in\na default configuration.\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "2fb4539f5c78f7037061265346f3992f54bcad67",
      "tree": "83c409caa7107abb154e29c3fa207554ba3c4973",
      "parents": [
        "19fdb4a229de5ea1fe306254aaae7802df638945"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Aug 17 21:42:58 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 00:09:14 2026 +0200"
      },
      "message": "time out writes to stalled TelnetAppender clients\n\nClients are written to synchronously while the appender lock is held and no\nSocket.SendTimeout was set anywhere, so a client that connects and then\nstops reading let TCP flow control fill its receive window and the server\nsend buffer. The next write blocked forever and every thread logging\nthrough the appender queued behind it. The existing eviction only fires on\na thrown exception, and a blocked write never throws.\n\nAccepted sockets now get a finite SendTimeout, configurable through the new\nSendTimeoutMillis property and defaulting to 5000. A timed-out write throws\nand the client is evicted like any other dead connection. Setting the\nproperty to 0 restores the previous unbounded behavior.\n\nSocketHandler gained a (port, sendTimeoutMillis) overload rather than an\noptional parameter, so the existing (port) signature keeps working for\nsubclasses; it maps to 0 to preserve its old semantics.\n\nWrites stay synchronous under the appender lock, so several stalled clients\nstill cost up to the timeout each. Moving the sends to a bounded per-client\nqueue would remove that entirely and is left as a follow-up.\n\nTelnetAppender had no page in the manual, which is added here, including\nthat it is a diagnostic tool for trusted networks and that the connecting\nclient is trusted, like any other appender destination.\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "19fdb4a229de5ea1fe306254aaae7802df638945",
      "tree": "4030bc4718aec5f10bd3d706add77cedf62124ca",
      "parents": [
        "9f5c955787ddeedf49792a4dd89156c40af87576"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Aug 17 21:31:39 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 00:09:14 2026 +0200"
      },
      "message": "warn when AdoNetAppender executes layout-generated SQL\n\nWithout CommandText the appender builds a complete SQL statement per event\nby rendering the Layout and executes it as it is. Layouts perform no SQL\nquoting or escaping and offer no way to add it, so anything that reaches a\nlog statement is executed as part of the statement, with the privileges of\nthe appender\u0027s connection.\n\nActivateOptions now logs an error naming the appender and pointing at\nCommandText with AdoNetAppenderParameter bindings, which pass content as\ndatabase parameters. The mode itself keeps working, so no existing\nconfiguration breaks.\n\nThe manual gained a warning as well, and its claim that BufferSize\ndefaults to 100 is corrected to 512.\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "9f5c955787ddeedf49792a4dd89156c40af87576",
      "tree": "9a23d364b8218acb829da996bcb03a7368fc5e0d",
      "parents": [
        "ecd1b8b9e26c8b4a5414d67c757b1ffc692b1355"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Aug 17 21:29:30 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 00:09:13 2026 +0200"
      },
      "message": "contain per-event failures in AdoNetAppender.SendBuffer\n\nEvents are removed from the CyclicBuffer by PopAll before SendBuffer runs,\nso they cannot be retried later. Neither ExecuteNonQuery loop contained\nper-event failures, and with UseTransactions (the default) a single event\nthe provider rejects - npgsql refuses U+0000, for example - rolled back\nthe whole batch of up to 512 events, including the ones logged before it.\nAn attacker who gets one such byte logged per flush window could suppress\nthe database audit trail indefinitely.\n\nWithout a transaction each event is now reported and skipped individually.\nIn transaction mode the exception still has to propagate, so the events\nare retried one by one after the rollback; only the events the database\nactually rejects are lost.\n\nThis makes delivery at-least-once: if the batch failed after the database\nhad already applied some statements, those events are written again.\nDuplicates are preferred over losing the whole buffer.\n\nLog4NetTransaction.Dispose threw NotImplementedException, which log4net\nswallowed in DoAppend, so no test ever exercised the rollback path. Real\nproviders roll back on Dispose rather than throwing.\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "ecd1b8b9e26c8b4a5414d67c757b1ffc692b1355",
      "tree": "1b1986167174a34df0eed3d7317bc28bd7393445",
      "parents": [
        "cf8aa32adbdd417b8982af579cb619781b2be92c"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Aug 17 21:29:19 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 18 00:09:12 2026 +0200"
      },
      "message": "report the first appender error without log4net.Internal.Debug\n\nOnlyOnceErrorHandler.FirstError only forwarded to LogLog when\nLogLog.InternalDebugging was set, which is off by default. Since every\nappender uses this handler by default, an appender that stopped\ndelivering events did so completely silently: no stderr line and no\nLogLog.LogReceived event, and the handler disables itself afterwards.\n\nThe condition was redundant anyway: LogLog.Error already checks\nLogLog.QuietMode (log4net.Internal.Quiet) and EmitInternalMessages, so\nboth documented ways of silencing internal messages keep working.\n\nUpgrade note: previously invisible appender errors are now visible, so a\nmisconfigured appender emits one log4net:ERROR line on stderr.\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\n"
    },
    {
      "commit": "cf8aa32adbdd417b8982af579cb619781b2be92c",
      "tree": "757f0efc0823e827b9258122c94a2f5efe17b379",
      "parents": [
        "3e23ae9eac63b71ddd109af2f03553c8b5938b7f",
        "1acfaa6a3e09770e22cc1b57f5902fda06bbfadc"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Aug 17 19:33:10 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Aug 17 19:33:10 2026 +0200"
      },
      "message": "Merge remote-tracking branch \u0027origin/master\u0027 into Feature/306-aot-calling-assembly\n"
    },
    {
      "commit": "1acfaa6a3e09770e22cc1b57f5902fda06bbfadc",
      "tree": "41083cd8e75aa425316f3dc8d055e028ac1302d1",
      "parents": [
        "a1eb07f1487972ee5b4f60971036f64dc44af7bb"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "43271715+FreeAndNil@users.noreply.github.com",
        "time": "Mon Aug 17 09:02:17 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Aug 17 09:02:17 2026 +0200"
      },
      "message": "bump js-yaml override to ^4.3.1 (#308) (#308)\n\nFixes quadratic CPU in !!omap resolution pulled in transitively via Antora.\nhttps://github.com/apache/logging-log4net/security/dependabot/81"
    },
    {
      "commit": "a1eb07f1487972ee5b4f60971036f64dc44af7bb",
      "tree": "3efdc01d8c4714c1f0a333a13c5ec4d649afaca3",
      "parents": [
        "1231d72f769cac100e17275e40a9f384abf564c3",
        "fe5997b1904bb9c1f32c18e639ac7a4f40608251"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "43271715+FreeAndNil@users.noreply.github.com",
        "time": "Mon Aug 17 06:55:49 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Aug 17 06:55:49 2026 +0200"
      },
      "message": "Merge pull request #307 from apache/Feature/307-cls-compliant\n\nmark log4net.Ext.Mail as CLS compliant (#307)"
    },
    {
      "commit": "3e23ae9eac63b71ddd109af2f03553c8b5938b7f",
      "tree": "909f0f5fc2b9c432c69b4528a0ede83550cbc2d5",
      "parents": [
        "364e0ee4823ef83264598ce40d866aa24caacf62"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Sun Aug 16 23:21:12 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Sun Aug 16 23:31:38 2026 +0200"
      },
      "message": "test what works under Native AOT (#306)\n\nAdd log4net.Tests.Aot, which runs the same probes JIT compiled and published with\nPublishAot and fails when either run differs from the expected list, and run it from\nCI. Silence log4net\u0027s internal messages while probing, because the probes report their\nown failures and a passing run that prints errors reads as a broken one.\n"
    },
    {
      "commit": "364e0ee4823ef83264598ce40d866aa24caacf62",
      "tree": "13d8813150f5a3864da3e3ca28fb6f0e25ec4750",
      "parents": [
        "ae3ee38586af5305de658d0b13c28f225ad9f912"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Sun Aug 16 23:18:12 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Sun Aug 16 23:18:12 2026 +0200"
      },
      "message": "enforce IDE0005 on build and remove unnecessary usings (#306)\n\nSet EnforceCodeStyleInBuild and GenerateDocumentationFile in Directory.Build.props,\nsuppress CS1591 for test and integration projects, and clear the 15 usings this\n  surfaced.\n"
    },
    {
      "commit": "fe5997b1904bb9c1f32c18e639ac7a4f40608251",
      "tree": "3efdc01d8c4714c1f0a333a13c5ec4d649afaca3",
      "parents": [
        "c9af89e5fe3e66f619ac4a1dcb130e578cc79565"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Sun Aug 16 21:44:43 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Sun Aug 16 21:44:43 2026 +0200"
      },
      "message": "fix macos CI build\n"
    },
    {
      "commit": "c9af89e5fe3e66f619ac4a1dcb130e578cc79565",
      "tree": "bc2c93670839b83ccc82185ff09c03ecda7b8732",
      "parents": [
        "1231d72f769cac100e17275e40a9f384abf564c3"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Sun Aug 16 21:25:38 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Sun Aug 16 21:25:38 2026 +0200"
      },
      "message": "mark log4net.Ext.Mail as CLS compliant (#307)\n"
    },
    {
      "commit": "ae3ee38586af5305de658d0b13c28f225ad9f912",
      "tree": "b2925d32383d5fa748da14ef702cef41e5d3ef31",
      "parents": [
        "f78341fcf5c15b20d0892d4a2aacb3242ad06a05"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Sun Aug 16 21:15:41 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Sun Aug 16 21:15:41 2026 +0200"
      },
      "message": "narrow the missing configuration system check (#306)\n\nAsk the runtime instead of guessing from the exception: Native AOT is identified by CallerAssembly.IsSupported, and elsewhere only a failure naming System.Configuration itself counts, so a broken app.config is still reported.\n"
    },
    {
      "commit": "f78341fcf5c15b20d0892d4a2aacb3242ad06a05",
      "tree": "b38e9acb35edaac388434caad21bc6ae724585eb",
      "parents": [
        "bf839f78293923425577bb6431de049a089d3a64"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Sun Aug 16 21:06:44 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Sun Aug 16 21:06:44 2026 +0200"
      },
      "message": "Copy the built-in ConverterInfo entries per parser instead of sharing them, make\n_configurationSystemUnavailable volatile, and fix the IsAndoid test name typo.\n"
    },
    {
      "commit": "1231d72f769cac100e17275e40a9f384abf564c3",
      "tree": "7261ce729125e27009756857652fefc6a77b92a2",
      "parents": [
        "9a64f95270ff1d0ff84bc02e2e3d757ae5076d44"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Thu Aug 06 22:56:01 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Thu Aug 06 22:56:01 2026 +0200"
      },
      "message": "graphify update\n"
    },
    {
      "commit": "bf839f78293923425577bb6431de049a089d3a64",
      "tree": "17d5417c2cf69f5099aa786f74f676186783ba47",
      "parents": [
        "9a64f95270ff1d0ff84bc02e2e3d757ae5076d44"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 05 23:06:59 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Thu Aug 06 22:35:09 2026 +0200"
      },
      "message": "make log4net usable from a PublishAOT build (#306)\n\nNative AOT broke log4net in three ways (#233).\n\nAssembly.GetCallingAssembly() throws PlatformNotSupportedException there, so\nevery overload that resolves the repository from the caller failed -\nLogManager.GetLogger(Type) among them. Guard the 18 call sites with\nCallerAssembly.IsSupported, a flag probed once, and fall back to the entry\nassembly when the runtime does not implement the call. The call itself has to\nstay in the public method whose caller is wanted, so it cannot be moved into\nthe helper.\n\nSystemInfo.GetAppSetting() then reported a caught failure on every lookup,\nbecause a trimmed System.Configuration cannot initialize. Tell that apart from\na configuration file that does not parse - Native AOT surfaces both as a\nConfigurationErrorsException, so only the inner exception distinguishes them -\nand treat a missing configuration system as a property of the runtime rather\nthan a fault: log it at debug level and let environment variables stand in for\nthe config file, as they already do on Android. A malformed config file is\nstill reported as an error and still yields no setting.\n\nFinally the trimmer removed the constructors of everything log4net creates\nreflectively, so no repository, pattern converter or locking model could be\ninstantiated. Annotate that flow with DynamicallyAccessedMembers - polyfilled\nhere, because the trimmer matches it by name and neither target framework\ndeclares it - and hold the built-in converters in a Dictionary of ConverterInfo\nrather than of Type, since a Type placed in a collection loses its annotation.\nThe registries are now built through a generic method whose new() constraint\nstates the same requirement structurally, so a converter without a public\nparameterless constructor fails to compile instead of failing in a trimmed\nbuild.\n\nConfiguration still has to be done in code: XmlConfigurator names its types in\nstrings and cannot work once they have been trimmed. Document that, and the\nfact that loggers from non-entry assemblies land in the entry assembly\u0027s\nrepository, on a new Native AOT page in the manual.\n"
    },
    {
      "commit": "9a64f95270ff1d0ff84bc02e2e3d757ae5076d44",
      "tree": "165d4ab1de27fdca1c6691ebecf8f38f96922148",
      "parents": [
        "d6fdd18007c49b32174e64c9e090a5ecdbfa7a26",
        "98742f239daec237c4fcbc35fe69c98b2abeedbe"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "43271715+FreeAndNil@users.noreply.github.com",
        "time": "Wed Aug 05 08:51:08 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Aug 05 08:51:08 2026 +0200"
      },
      "message": "dotnet 10 build cleanup (#305)\n\n## Why\n\nThe sources already use C# 14 (the `field` keyword in `SmtpAppender`\u0027s property accessors), which\nrequires the .NET 10 SDK. Nothing in the repo declared that: the test projects targeted `net8.0`,\nCI installed .NET 8 and the Dockerfile fetched the 8.0 channel, so a clean checkout could not\ncompile - it failed with `CS0501: \u0027SmtpAppender.To.get\u0027 must declare a body`.\n\nThis PR makes the required toolchain explicit and cleans up the surrounding build, which turned up\nseveral unrelated defects along the way.\n\n**The shipped surface is unchanged.** `log4net` still targets `net462;netstandard2.0` and\n`log4net.Ext.Mail` still targets `netstandard2.0`. Nothing here affects consumers.\n\n## Changes\n\n| Commit | What |\n|---|---|\n| Target .NET 10 / C# 14 | test and integration-test projects `net8.0` → `net10.0`; CI `dotnet-version: 10` |\n| Build net4x without Mono | delete `MonoForFramework.targets` and its two imports |\n| Container image from the .NET 10 SDK image | `ubuntu:20.04` + `dotnet-install.sh` →\n`mcr.microsoft.com/dotnet/sdk:10.0-noble` |\n| Stop the release scripts on failed steps | `$PSNativeCommandUseErrorActionPreference` in both scripts, plus a path\nfix |\n| Fix the log4net.Ext.Mail package readme | `NU5039` |\n| Quieten the TelnetAppender test | graceful socket shutdown |\n| Update BUILDING.md | document what the build actually is |\n\n### Mono is no longer needed to build net4x\n\n`MonoForFramework.targets` set `FrameworkPathOverride` to Mono\u0027s `4.6.2-api` directory on Unix. That\nis obsolete: the .NET SDK already adds an implicit `PackageReference` to\n`Microsoft.NETFramework.ReferenceAssemblies.\u003ctfm\u003e` for net4x targets, and those packages were\nalready in the restore graph.\n\n### net462 tests are now Windows-only\n\nVSTest hosts net4x tests through `TestHostNetFramework/testhost.exe`, a .NET Framework executable,\nso `dotnet test` aborts with `TESTRUNABORT` on Linux and macOS. `log4net.Tests` now conditions its\n`TargetFrameworks` on `\u0027$(OS)\u0027 !\u003d \u0027Windows_NT\u0027`, so no unrunnable test assembly is produced. The\n`net462` **library** is still built on every platform; only the test target is gated.\n\nThis also fixes the `ubuntu-22.04` and `macos-14` CI jobs, which ran a bare `dotnet test` against a\n`net462` target they could not host.\n\n###  Run CI on the latest runner images\n\nmacos-14 and ubuntu-22.04 are superseded by macos-latest (macOS 26) and ubuntu-latest (Ubuntu 24.04).\nNeither new image ships Mono, so net4x tests cannot run there - which is why log4net.Tests restricts net462 to Windows.\n\n### Release scripts continued after failed steps\n\n`$ErrorActionPreference \u003d \u0027Stop\u0027` does not apply to native commands — they only set\n`$LASTEXITCODE`. A failing `dotnet`, `git`, `zip`, `gpg` or `mvnw` was therefore ignored, and\nartifacts were packaged, signed and tagged anyway. Both scripts now set\n`$PSNativeCommandUseErrorActionPreference` (PowerShell 7.3+).\n\nThis was not theoretical: `NU5039` made the `log4net.Ext.Mail` pack fail, no `.nupkg` was produced,\nand `build-preview.ps1` went on to gpg-sign files that did not exist. `build-preview.ps1` also built\nits artifact paths with backslashes, which are not path separators outside Windows.\n\n### TelnetAppender test noise\n\n`SimpleTelnetClient.Dispose()` disposed the `TcpClient` while the reader was blocked in\n`stream.Read`, so teardown aborted the socket and dumped an `IOException` with a stack trace on\nevery passing run. The cancellation token never actually broke the loop — it was only checked after\na successful read. Now the socket is shut down first, the read returns 0, and the loop exits\nnormally. Exceptions arriving after disposal starts are not reported; genuine failures still are.\n\n## Verification\n\nOn Linux (Ubuntu-based, .NET SDK 10.0.110, self-built Mono present but unused by the build):\n\n- `dotnet build ./src/log4net.sln` - succeeds, 0 warnings\n- `dotnet test ./src/log4net.sln` - **292 total, 0 failed, 281 succeeded**, 11 skipped (Windows-only)\n- `net462` and `net472` compile with `MonoForFramework.targets` deleted\n- `log4net.Tests.Signing.AssemblyShouldBeSigned` passes - strong naming survives the\n  reference-assembly switch\n- `./mvnw site` works\n- both scripts parse under pwsh 7.6.4; the native-error behaviour was verified directly\n\n## For reviewers to weigh\n\n**Nothing tests on the .NET 8 runtime any more.** `netstandard2.0` consumers on .NET 8 (LTS until\nNovember 2026) are still supported but no longer exercised.\n\n**The MCR image reference is fully qualified**, so it needs no registry configuration and no login."
    },
    {
      "commit": "98742f239daec237c4fcbc35fe69c98b2abeedbe",
      "tree": "165d4ab1de27fdca1c6691ebecf8f38f96922148",
      "parents": [
        "cfeb2e5da662ac1f6914ac5729cd04bae07574be"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 05 00:19:51 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 05 00:30:22 2026 +0200"
      },
      "message": "Remove the Mono guards from the tests (#305)\n\nUtils.IsMono and Utils.InconclusiveOnMono are gone, along with all 15 call sites.\nThe net462 tests run only on Windows now and the net10.0 tests run on .NET 10, so the guard could never fire.\n\nSystemInfo.IsMono in the library is deliberately untouched: it detects the runtime executing log4net, which can still be Mono.\n"
    },
    {
      "commit": "cfeb2e5da662ac1f6914ac5729cd04bae07574be",
      "tree": "a10e3870914803a2c4a06e3ee625d5c90419bce2",
      "parents": [
        "a73070c590be08aa12f942878605e964d5f91b36"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 05 00:03:21 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 05 00:30:21 2026 +0200"
      },
      "message": "Run CI on the latest runner images (#305)\n\n  macos-14 and ubuntu-22.04 are superseded by macos-latest (macOS 26) and\n  ubuntu-latest (Ubuntu 24.04). Neither new image ships Mono, so net4x\n  tests cannot run there - which is why log4net.Tests restricts net462 to\n  Windows. Correct the reason given in BUILDING.md and the changelog.\n"
    },
    {
      "commit": "a73070c590be08aa12f942878605e964d5f91b36",
      "tree": "2f65f006d294dccaaf3bd0101a53314939430218",
      "parents": [
        "d398490149df57cdb50456afda81f5039ea1fb3c"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 04 23:43:44 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 05 00:30:21 2026 +0200"
      },
      "message": "Update BUILDING.md to match the actual build\n"
    },
    {
      "commit": "d398490149df57cdb50456afda81f5039ea1fb3c",
      "tree": "80f3a40f87b1f7e6148aacb82fef5dbb17241b3f",
      "parents": [
        "9fab1adbd72b50f2acb0a9b1569316c475611586"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 04 23:37:41 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 05 00:30:21 2026 +0200"
      },
      "message": "Quieten the TelnetAppender test\n\n  Dispose disposed the TcpClient while the reader was blocked in\n  stream.Read, so teardown always aborted the socket and dumped an\n  IOException with a stack trace, even on a passing run. Shut the socket\n  down first, so the read returns 0 and the loop ends normally, and only\n  report exceptions that arrive before disposal. Progress chatter removed;\n  the test now prints nothing unless it fails.\n\n  Two things this fixes beyond the noise:\n\n  - The cancellation token never actually stopped the loop. The check ran only after a successful read, so the reader\n  could only be broken by disposing the socket under it. Now Shutdown(SocketShutdown.Both) ends the stream and the loop\n  exits through its normal condition.\n  - Diagnostics are preserved for real failures. log is still wired to TestContext.Out.WriteLine, gated on !_disposing - so a genuine client error still surfaces, and Assert.Fail on timeout still reports what was received.\n"
    },
    {
      "commit": "9fab1adbd72b50f2acb0a9b1569316c475611586",
      "tree": "769cf807416c738ba55f684a18cf4204bd881deb",
      "parents": [
        "96123c999540ccaed5c089db7738b549a6ccda24"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 04 23:35:27 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 05 00:30:20 2026 +0200"
      },
      "message": "Fix the log4net.Ext.Mail package readme\n\n  PackageReadmeFile requires the readme at the package root, so packing\n  README.md without a PackagePath failed with NU5039. Matches the pattern\n  already used in log4net.csproj.\n"
    },
    {
      "commit": "96123c999540ccaed5c089db7738b549a6ccda24",
      "tree": "fdcc479cb52b86b0b7721f491bad1bbb557496a9",
      "parents": [
        "27216417ce4fe9410b64d6af14cf676ce71dace1"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 04 23:34:49 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 05 00:30:20 2026 +0200"
      },
      "message": "Stop the release scripts on failed steps\n\n  $ErrorActionPreference does not apply to native commands, so a failing\n  dotnet, git, zip, gpg or mvnw was ignored and the artifacts were\n  packaged, signed and tagged anyway. Both scripts now set\n  $PSNativeCommandUseErrorActionPreference (PowerShell 7.3+).\n\n  Also fix build-preview.ps1 outside Windows, where the artifact paths\n  handed to gpg used backslashes.\n"
    },
    {
      "commit": "27216417ce4fe9410b64d6af14cf676ce71dace1",
      "tree": "12520270940d0d4e76892973614f62d34f85ab27",
      "parents": [
        "7f63f49035e94b2d93eb28c1ad4fe9f99f412db1"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 04 23:33:28 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 05 00:30:20 2026 +0200"
      },
      "message": "Build the container image from the .NET 10 SDK image\n\n  Replace ubuntu:20.04 + dotnet-install.sh with\n  mcr.microsoft.com/dotnet/sdk:10.0-noble - Ubuntu 24.04 with the SDK\n  preinstalled. Drops the Mono packages, the apt-key/stable-focal repo,\n  wget, tree and the DOTNET_ROOT/PATH handling, leaving no apt layer at\n  all. Ubuntu 20.04 left standard support in April 2025.\n"
    },
    {
      "commit": "7f63f49035e94b2d93eb28c1ad4fe9f99f412db1",
      "tree": "447e26ca52b58b23f48fb7dfb77a74b6d137f0c6",
      "parents": [
        "c9e278b2c29944c9d2eadd310e66a8016d21eebf"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 04 23:26:06 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 05 00:30:20 2026 +0200"
      },
      "message": "Build net4x without Mono\n\n  Remove MonoForFramework.targets and its FrameworkPathOverride handling.\n  The net462/net472 targets compile against the   Microsoft.NETFramework.ReferenceAssemblies packages that the .NET SDK\n  already references implicitly, so Mono is only needed to run .NET\n  Framework assemblies - not to build them (and mono is now deprecated by Microsoft).\n"
    },
    {
      "commit": "c9e278b2c29944c9d2eadd310e66a8016d21eebf",
      "tree": "fa198b69cc2394f68516614cf7f7c740114a2fdb",
      "parents": [
        "d6fdd18007c49b32174e64c9e090a5ecdbfa7a26"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 04 23:24:15 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Aug 05 00:30:19 2026 +0200"
      },
      "message": "Target .NET 10 / C# 14 for tests\n\n  The sources use C# 14, so a .NET 10 SDK is now required. Test and\n  integration-test projects move from net8.0 to net10.0; the shipped\n  log4net assembly keeps net462;netstandard2.0.\n"
    },
    {
      "commit": "d6fdd18007c49b32174e64c9e090a5ecdbfa7a26",
      "tree": "5fdc4061e9eb2077c53679dc81025f2fd4fd84c5",
      "parents": [
        "1a54369bb1939b12178c1112fc76784e9c09d68a"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 04 21:27:35 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 04 21:27:35 2026 +0200"
      },
      "message": "update version\n"
    },
    {
      "commit": "1a54369bb1939b12178c1112fc76784e9c09d68a",
      "tree": "e580a0f40e84992c6e07c64c2c9b4a4197be8ab0",
      "parents": [
        "29a21046be37ce8b912237bac70d46c785de4e69"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 04 21:25:46 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 04 21:25:46 2026 +0200"
      },
      "message": "Update version to 3.4.0\n"
    },
    {
      "commit": "29a21046be37ce8b912237bac70d46c785de4e69",
      "tree": "7f055c5640f2796f0e13c550532dc02fcdb77c93",
      "parents": [
        "ab8d11391236a9e6ebc965960ef8b95cb314baba"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "43271715+FreeAndNil@users.noreply.github.com",
        "time": "Tue Aug 04 20:49:30 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Aug 04 20:49:30 2026 +0200"
      },
      "message": "Fix `LoggingEvent.UserName` resolving the Windows identity for every event (#304)\n\nThe cache added in 2.0.15 (commit 9305ea9b) was declared as an instance field\non `LoggingEvent`. Since every event is a fresh instance the guard was always\nfalse, so the `??\u003d` never hit and each event ran a full\n`WindowsIdentity.GetCurrent().Name` - measured at 79.6 us on the machine used\nhere. The same commit had changed `TryGetCurrentUserName` from static to\ninstance, so the caching it introduced has never taken effect.\n\nThe doc comment above the property already described the intended design and\nthe reason it was abandoned: the name should be cached \"as long as the identity\nstayed constant\", but `WindowsIdentity.GetCurrent()` \"seems to return different\nobjects every time\". Object identity was the wrong comparison. The security\nidentifier is stable, and obtaining the identity is far cheaper than resolving\nits name - the timing table in that same comment puts the two at roughly 20 ns\nagainst 804 ns.\n\nSo the name is now cached without changing what the property reports:\n\n- A thread that is not impersonating runs as the process identity, so its name\n  is resolved once per process. `WindowsIdentity.GetCurrent(ifImpersonating:\n  true)` answers that question for 249 ns against 78 us for a name, making this\n  the fast path for services, console applications and ASP.NET Core.\n- A thread that is impersonating - classic ASP.NET with\n  `\u003cidentity impersonate\u003d\"true\"/\u003e`, or `RunImpersonated` - has its name\n  resolved once per distinct user, keyed by security identifier and capped at\n  `MaxCachedUserNames` entries so that a site in front of a large directory\n  cannot accumulate one entry per visitor.\n\nThe process-identity value is assigned in exactly one place, inside the branch\nthat has already established the thread is not impersonating. Seeding it from\nan impersonating thread would report that user for the rest of the process,\nwhich `ImpersonationDoesNotSeedTheProcessUserName` guards against.\n\nA buffered `FixFlags.All` event goes from 192,937 to 17,578 ns on this machine,\nboth sides built as netstandard2.0. The remainder is `FixFlags.LocationInfo`,\nwhich is untouched here.\n\nTwo related changes in the same method:\n\n- `Environment.UserName`, the fallback when `WindowsIdentity` is unusable, is\n  also cached; it measured 33.8 us per call. Impersonation does not apply on\n  that path.\n- The `SecurityException` handler now sets the unavailable flag, as the\n  `PlatformNotSupportedException` handler already did. Under partial trust the\n  old code threw, caught and logged once per event forever.\n\nDocumentation: the `%username` pattern entry now explains the caching and\npoints ASP.NET users at `%identity`, which is both cheaper and usually what is\nwanted because it reports the authenticated application user. The\n`BufferingForwardingAppender` manual page recommends `Partial` in its example\ninstead of `All`; the surrounding comment already warned that the `All` default\n\"may negatively impact performance enough to warrant changing it\", and\n`LocationInfo` costs 6.9 us and 14 kB per event.\n\n`LogicalThreadContextProperties` no longer stores an empty dictionary just to\nreplace it on the next line, and no longer clones on removal of an absent key.\nBoth are cleanups; neither changes the allocation profile of the common\nset/remove pattern."
    },
    {
      "commit": "ab8d11391236a9e6ebc965960ef8b95cb314baba",
      "tree": "cc12a109949138d1637bb03a538cc1ae371b501c",
      "parents": [
        "3671c78d2d92a58ad5610dfbffe784739f9169f0"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 04 10:30:16 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 04 10:30:16 2026 +0200"
      },
      "message": "separated readme for log4net.Ext.Mail\n"
    },
    {
      "commit": "3671c78d2d92a58ad5610dfbffe784739f9169f0",
      "tree": "f23ce39e844bfc3bf7b76dcfb780e24542829e21",
      "parents": [
        "0afea8c0eda674aa23abfcbee3a65b5a241252dc"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "43271715+FreeAndNil@users.noreply.github.com",
        "time": "Tue Aug 04 10:05:37 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Aug 04 10:05:37 2026 +0200"
      },
      "message": "log4net.Ext.Mail (#302)\n\n* #300 create new assemblies for SmtpAppender\n\n* add MailKit based SmtpAppender to log4net.Ext.Mail\n\nlog4net.Ext.Mail.Appender.SmtpAppender exposes the same options as\nlog4net.Appender.SmtpAppender, but sends via MailKit instead of the obsolete\nSystem.Net.Mail.SmtpClient. Sending goes through the new ISmtpTransport\nabstraction (default: MailKitSmtpTransport) so the appender can be tested\nwithout an SMTP server.\n\n* add tests for the MailKit based SmtpAppender\n\n* - TelnetAppender: register client before sending welcome banner\n  (log messages could be dropped via HasConnections race)\n- test: free TCP port, locked receive buffer, assert on stream\n  content instead of read count, 30s timeout, log client errors\n\n* Move ISmtpTransport and MailKitSmtpTransport to Appender/Internal\n\n* Make the MailKit transport internal\n\n* document the MailKit based SmtpAppender\n\nRecommend the MailKit appender from log4net.Ext.Mail over the built-in one,\nwhich relies on the deprecated System.Net.Mail.SmtpClient, and port all\nconfiguration samples to the new type. Adds the changelog entry for #300.\n\n* simplify type in return statement\n\n* fix PackageVersion for MauiTestApplication\n\n* Deprecate the built-in SmtpAppender and release log4net.Ext.Mail #300"
    },
    {
      "commit": "0afea8c0eda674aa23abfcbee3a65b5a241252dc",
      "tree": "339daf080f94a94912d17e5bbae9df37e23a476a",
      "parents": [
        "276c3afba226e0006583d73c44da588f04c82405"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 04 08:29:39 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Aug 04 08:29:39 2026 +0200"
      },
      "message": "graphify update\n"
    },
    {
      "commit": "276c3afba226e0006583d73c44da588f04c82405",
      "tree": "fb412109e9b6b69321df6be8e57ffa83921f8d37",
      "parents": [
        "839191e777ddd0f0729794ace06272ad670ba221"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Aug 03 16:33:49 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Aug 03 16:33:49 2026 +0200"
      },
      "message": "document raw string usage\n"
    },
    {
      "commit": "839191e777ddd0f0729794ace06272ad670ba221",
      "tree": "56945bf26f955a2b7bf19887d60e96233fc49b9e",
      "parents": [
        "d5cd98045d302ceea1f39579b2ed964312df404d"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Jul 28 22:35:34 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Jul 28 22:35:34 2026 +0200"
      },
      "message": "documented \"Omit the type wherever the target is known\"\n"
    },
    {
      "commit": "d5cd98045d302ceea1f39579b2ed964312df404d",
      "tree": "19b9c8554cedc7ebf875c9a1290883c12198d10e",
      "parents": [
        "9b8a8ad5c515f6e3ec73222e54b40718b817062a"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Jul 28 22:27:41 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Jul 28 22:27:41 2026 +0200"
      },
      "message": "document the EnsureNotNull convention\n"
    },
    {
      "commit": "9b8a8ad5c515f6e3ec73222e54b40718b817062a",
      "tree": "538f90ccb8724400016ef8f00c2fc65ae32deb44",
      "parents": [
        "13b52ab9b6edab14d32ee24bfeb700541cfd8119"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Jul 28 17:41:51 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Jul 28 17:41:51 2026 +0200"
      },
      "message": "added styleguide\n"
    },
    {
      "commit": "13b52ab9b6edab14d32ee24bfeb700541cfd8119",
      "tree": "7964edc5ef9468635c4b844c1649d60366041f8f",
      "parents": [
        "0a9327e9d485e57c9f8db3cff2eac280a18a8c2d"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "43271715+FreeAndNil@users.noreply.github.com",
        "time": "Tue Jul 28 16:15:42 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Jul 28 16:15:42 2026 +0200"
      },
      "message": "Pin js-yaml to ^4.3.0 via npm override (#301)\n\nhttps://github.com/apache/logging-log4net/security/dependabot/80\n\nAntora 3.2.0-rc.2 requires js-yaml ~4.2, which excludes the 4.3.0\nrelease that fixes the merge-key quadratic CPU consumption advisory.\nNo newer Antora is published, so override js-yaml directly.\nDocs build verified with the overridden version."
    },
    {
      "commit": "0a9327e9d485e57c9f8db3cff2eac280a18a8c2d",
      "tree": "3c97a06a35b6a5e03adb3caf705907cb4cad7365",
      "parents": [
        "f9770fd8e294823891998a07e17524785a8c2866"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Jul 27 14:04:21 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Jul 27 14:04:21 2026 +0200"
      },
      "message": "graphify test\n"
    },
    {
      "commit": "f9770fd8e294823891998a07e17524785a8c2866",
      "tree": "2d2892a4268bd90cec1a91669c985b954396ff6f",
      "parents": [
        "060b3b5fd4c560af5eea0f10b3f17f248c5bed5f"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Thu Jun 25 22:08:01 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Jun 25 22:08:01 2026 +0200"
      },
      "message": "Bump js-yaml, @antora/cli and @antora/site-generator-default (#299)\n\n---\nupdated-dependencies:\n- dependency-name: js-yaml\n  dependency-version: 4.2.0\n  dependency-type: indirect\n- dependency-name: \"@antora/cli\"\n  dependency-version: 3.2.0-rc.2\n  dependency-type: direct:development\n- dependency-name: \"@antora/site-generator-default\"\n  dependency-version: 3.2.0-rc.2\n  dependency-type: direct:development\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "060b3b5fd4c560af5eea0f10b3f17f248c5bed5f",
      "tree": "cb9b7378ff3cfb0e8021a6b14e2fda1e7de13ab5",
      "parents": [
        "7f7d46628aee0746524f106253fbd44bcb10e481"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Thu Jun 25 21:59:12 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Thu Jun 25 21:59:12 2026 +0200"
      },
      "message": "bump version for 3.3.3\n"
    },
    {
      "commit": "7f7d46628aee0746524f106253fbd44bcb10e481",
      "tree": "550f38af195dbc77e05f9427ebc41cabcdd54ee3",
      "parents": [
        "0cd39cb1165c3bbb4e86d5f26b113d7deb7cd4ba"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Jun 22 22:13:35 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Jun 22 22:13:35 2026 +0200"
      },
      "message": "adjust release date\n"
    },
    {
      "commit": "0cd39cb1165c3bbb4e86d5f26b113d7deb7cd4ba",
      "tree": "52ff70a4b285b82ae74283d180a245f0a949470f",
      "parents": [
        "e633f774068d6a9114ac7c5945f5656af03a0f4d",
        "2a0a19018775ed55be66eea5e33dbe5e6164a33a"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "43271715+FreeAndNil@users.noreply.github.com",
        "time": "Mon Jun 22 13:08:33 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Jun 22 13:08:33 2026 +0200"
      },
      "message": "Fixes after AVSS scanning #298\n\nFixes for https://github.com/apache/tooling-agents/blob/main/ASVS/reports/logging-log4net/f57d7b3/issues.md\n\n---\n## Issue: FINDING-001 - Filter chain modification methods lack synchronization, creating potential race with FilterEvent under active logging\n**Labels:** bug, security, priority:low\n**Description:**\n\n### Summary\nThe `AddFilter` and `ClearFilters` methods in `AppenderSkeleton.cs` lack proper synchronization, creating a race condition with `FilterEvent` during active logging operations. This can lead to inconsistent filter chain state, potentially causing filters to be skipped, `NullReferenceException`, or lost filter entries.\n\n### Details\n**CWE:** CWE-362 (Concurrent Execution using Shared Resource with Improper Synchronization)  \n**ASVS:** 15.4.1 (L3)\n\n**Data Flow:**\n- `AddFilter` (no lock) → modifies `FilterHead`/`_tailFilter`/`filter.Next`\n- `FilterEvent` (under `LockObj` in `DoAppend`) reads `FilterHead` and traverses `f.Next`\n\n**Attack Vector:**\nIn-process code within the trust boundary calling `AddFilter`/`ClearFilters` concurrently with active logging—for example, during dynamic reconfiguration while the appender is receiving log events.\n\n**Impact:**\nInconsistent filter chain state during traversal in `FilterEvent`, resulting in:\n- Filters being skipped during evaluation\n- `NullReferenceException` during chain traversal\n- Lost filter entries\n\n### Remediation\nAdd `lock(LockObj)` to both `AddFilter` and `ClearFilters` methods to synchronize with the `DoAppend` hot path and ensure thread-safe filter chain modifications.\n\n### Acceptance Criteria\n- [x] Fixed: `AddFilter` method wrapped with `lock(LockObj)`\n- [x] Fixed: `ClearFilters` method wrapped with `lock(LockObj)`\n- [x] Test added: Concurrent filter modification during active logging\n\n### References\n- File: `src/log4net/Appender/AppenderSkeleton.cs`\n- Source Report: 15.4.1.md\n\n### Priority\n**Low** - Requires in-process code with concurrent reconfiguration during active logging. Limited to availability/integrity impact within the logging subsystem.\n\n---\n## Issue: FINDING-002 - InterProcessLock Mutex Not Released When Underlying File Stream Is Null\n**Labels:** bug, security, priority:low\n**Description:**\n\n### Summary\nWhen `InterProcessLock.AcquireLock()` is called and the underlying `_stream` is null (due to a prior file open failure), the named Mutex is acquired but never released. This causes a resource leak that blocks other processes attempting to use InterProcessLock on the same file, potentially leading to deadlock or resource exhaustion.\n\n### Details\n**CWE:** CWE-772 (Missing Release of Resource after Effective Lifetime)  \n**ASVS:** 1.4.3 (L2)\n\n**Data Flow:**\n1. `InterProcessLock.AcquireLock()` called with `_stream \u003d\u003d null`\n2. `_mutex.WaitOne()` acquires the named Mutex\n3. `_recursiveWatch` is incremented\n4. Method returns null without releasing the mutex\n5. Caller (`FileAppender.Append`) does not enter try/finally block\n6. `ReleaseLock()` is never called\n7. Named system Mutex remains held indefinitely\n\n**Attack Vector:**\nNot directly exploitable by external attackers. Requires environmental file open failure (e.g., permissions, disk full, file locked by another process).\n\n**Impact:**\n- Named Mutex remains held indefinitely\n- Other processes using InterProcessLock on the same file are blocked\n- Potential deadlock across processes\n- Resource exhaustion if multiple locks are leaked\n\n### Remediation\nRelease the named Mutex immediately when `AcquireLock()` detects that `_stream` is null:\n1. Decrement `_recursiveWatch`\n2. Call `_mutex.ReleaseMutex()`\n3. Return null\n\nEnsure all code paths that acquire the mutex properly release it, even in error conditions.\n\n### Acceptance Criteria\n- [x] Fixed: Mutex released when `_stream` is null in `AcquireLock()`\n- [x] Fixed: `_recursiveWatch` properly decremented in error path\n- [x] Test added: Verify mutex released when file stream is null\n\n### References\n- File: `src/log4net/Appender/FileAppender.cs`\n- Source Report: 1.4.3.md\n\n### Priority\n**Low** - Requires environmental file system failure. Impact limited to inter-process synchronization and resource exhaustion within logging subsystem.\n\n---\n## Issue: FINDING-003 - Finalizer path lacks exception protection, risking process termination\n**Labels:** bug, security, priority:low\n**Description:**\n\n### Summary\nThe `~AppenderSkeleton()` finalizer calls `Close()` which in turn calls `OnClose()` without exception protection. An unhandled exception on the finalizer thread will terminate the entire process in .NET Framework 2.0+ and .NET Core/5+.\n\n### Details\n**CWE:** CWE-755 (Improper Handling of Exceptional Conditions)  \n**ASVS:** 16.5.4 (L3)\n\n**Data Flow:**\nGC finalizer thread → `~AppenderSkeleton()` → `Close()` → `OnClose()` (subclass implementation) → unhandled exception → **process termination**\n\n**Attack Vector:**\nIf a subclass implementation of `OnClose()` throws an unhandled exception during finalization (e.g., due to resource cleanup failure, network timeout, or malformed state), the finalizer thread will propagate the exception and terminate the entire application process.\n\n**Impact:**\n- Complete application/service termination\n- Denial of service\n- Loss of in-flight data\n- Ungraceful shutdown without proper cleanup\n\n### Remediation\n1. Wrap the finalizer\u0027s call to `Close()` in a try-catch block:\n   ```csharp\n   catch (Exception ex) when (!ex.IsFatal())\n   {\n       // Log if possible, otherwise suppress\n   }\n   ```\n2. Consider protecting `Close()` itself with exception handling\n3. Ensure `_isClosed` is set in a finally block to prevent repeated finalization attempts\n\n### Acceptance Criteria\n- [x] Fixed: Finalizer wrapped with try-catch for non-fatal exceptions\n- [x] Fixed: `_isClosed` flag set in finally block\n- [x] Code review: Verify fatal exceptions (OutOfMemoryException, StackOverflowException) are not caught\n\n### References\n- File: `src/log4net/Appender/AppenderSkeleton.cs`\n- Source Report: 16.5.4.md\n\n### Priority\n**Low** - Requires specific failure conditions during finalization. However, impact is severe (process termination) when triggered. Recommend prioritizing fix despite low likelihood."
    },
    {
      "commit": "2a0a19018775ed55be66eea5e33dbe5e6164a33a",
      "tree": "52ff70a4b285b82ae74283d180a245f0a949470f",
      "parents": [
        "3113aa8aee472edb7de73bf066d5a56c494ba520"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Jun 22 00:14:51 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Mon Jun 22 00:36:19 2026 +0200"
      },
      "message": "added unit tests\n"
    },
    {
      "commit": "3113aa8aee472edb7de73bf066d5a56c494ba520",
      "tree": "cb9741af248c795f013a50f3214b11ee419c52af",
      "parents": [
        "43d24247b7e32839efb6e0e5b06a56570b919d6c"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Sun Jun 21 23:37:17 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Sun Jun 21 23:37:27 2026 +0200"
      },
      "message": "Fix unhandled exception in AppenderSkeleton finalizer isking process termination\nWrap Close() in the finalizer with try-catch for non-fatal exceptions and move _isClosed into a finally block to prevent repeated finalization attempts (CWE-755)\n"
    },
    {
      "commit": "43d24247b7e32839efb6e0e5b06a56570b919d6c",
      "tree": "cf20f9b460d14d962167e48db72df849e6b2d323",
      "parents": [
        "9dd998ab6d50e40ce1c01ab6c7fa851006e3a769"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Sun Jun 21 23:24:52 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Sun Jun 21 23:25:07 2026 +0200"
      },
      "message": "Fix mutex leak in InterProcessLock.AcquireLock when file stream is null\nRelease acquired mutex and decrement recursiveWatch when stream is null to prevent indefinite blocking of other processes (CWE-772)\n"
    },
    {
      "commit": "9dd998ab6d50e40ce1c01ab6c7fa851006e3a769",
      "tree": "92ac3e67817b19fc1ac57502a7c7848a6426613b",
      "parents": [
        "e633f774068d6a9114ac7c5945f5656af03a0f4d"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Sun Jun 21 23:18:10 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Sun Jun 21 23:18:10 2026 +0200"
      },
      "message": "Fix race condition in AppenderSkeleton filter chain modification\nAdd lock(LockObj) to AddFilter and ClearFilters to synchronize with FilterEvent under concurrent logging (CWE-362).\n"
    },
    {
      "commit": "e633f774068d6a9114ac7c5945f5656af03a0f4d",
      "tree": "a2d836f2862ae0a88c2bc587f2a5d382d8b9826d",
      "parents": [
        "f57d7b3f5dae7a9d98a0f6a967a8eb01eab45ade"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Sun Jun 21 23:07:27 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Sun Jun 21 23:07:27 2026 +0200"
      },
      "message": "update .gitignore\n"
    },
    {
      "commit": "f57d7b3f5dae7a9d98a0f6a967a8eb01eab45ade",
      "tree": "f850ca73da42f3f5f3ed4c4ab56c101f966f8405",
      "parents": [
        "88c0576bfecc89c04bde37dc78603c0837ee337e"
      ],
      "author": {
        "name": "The Apache Software Foundation",
        "email": "root-asf-gitbox-commits@apache.org",
        "time": "Sat May 16 16:04:48 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat May 16 23:04:48 2026 +0200"
      },
      "message": "Set up default protection ruleset for default and release branches (#295)"
    },
    {
      "commit": "88c0576bfecc89c04bde37dc78603c0837ee337e",
      "tree": "3b0f53c649e314eaeb9c387c1fa20d4036bd2c4d",
      "parents": [
        "0cb33671444b64628deb8e306c400b027a3e87ed"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed May 13 14:59:45 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed May 13 14:59:45 2026 +0200"
      },
      "message": "added release note for #292\n"
    },
    {
      "commit": "0cb33671444b64628deb8e306c400b027a3e87ed",
      "tree": "2a002817a274f7eab4b66b02995b1799f3be1c27",
      "parents": [
        "44e9c13d5ffb9afacadc754e11afd89ee294ab5e"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed May 13 13:09:12 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed May 13 13:09:12 2026 +0200"
      },
      "message": "$(MSBuildThisFileDirectory) without \\\n"
    },
    {
      "commit": "44e9c13d5ffb9afacadc754e11afd89ee294ab5e",
      "tree": "13214c22094ebe67ad001db6f7194eef8ef1438d",
      "parents": [
        "fcb0f05ac29d28d5cbda0c18e4b922a9ae489a8e"
      ],
      "author": {
        "name": "Grzegorz Dziadkiewicz",
        "email": "grzegorz@dziadkiewicz.com",
        "time": "Sat May 09 16:54:09 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat May 09 16:54:09 2026 +0200"
      },
      "message": "Fix race in Hierarchy.TryCreateLogger (#294)\n\n* Add the repro project from #292\n\n* Add the repro for #292 as test\n\n* Add dotted logers tests and GetCurrentLoggers tests\n\nCo-authored-by: Copilot \u003ccopilot@github.com\u003e\n\n* Use one lock approach and add marker interface\n\n* Implement TODOs\n\n* Fix mistaken in if -\u003e switch refactor and adjust test for scenario with locking\n\n* PR upgrades\n\n* Potential fix for pull request finding\n\nCo-authored-by: Copilot Autofix powered by AI \u003c175728472+Copilot@users.noreply.github.com\u003e\n\n* PR upgrades 2\n\n---------\n\nCo-authored-by: Copilot \u003ccopilot@github.com\u003e\nCo-authored-by: Copilot Autofix powered by AI \u003c175728472+Copilot@users.noreply.github.com\u003e"
    },
    {
      "commit": "fcb0f05ac29d28d5cbda0c18e4b922a9ae489a8e",
      "tree": "a282d79190851e29cc2f3fca9c41a627f7d31c96",
      "parents": [
        "783570c43bd3d4e366326abca7f4b7dc2653ee4e"
      ],
      "author": {
        "name": "Grzegorz Dziadkiewicz",
        "email": "grzegorz@dziadkiewicz.com",
        "time": "Wed Apr 22 21:03:45 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Apr 22 21:03:45 2026 +0200"
      },
      "message": "Add Grzegorz Dziadkiewicz to list of active commiters (#293)"
    },
    {
      "commit": "783570c43bd3d4e366326abca7f4b7dc2653ee4e",
      "tree": "1fc40bf8b7ac5f4fff389680d02e6ce94b3669bd",
      "parents": [
        "14d8742b3c39ecff842be2dd999ca622d3950c67"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Sun Apr 19 21:53:36 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Sun Apr 19 21:53:36 2026 +0200"
      },
      "message": "bump version to 3.3.2\n"
    },
    {
      "commit": "14d8742b3c39ecff842be2dd999ca622d3950c67",
      "tree": "c609b9207b9064096cb697d23346bea80f6ee269",
      "parents": [
        "7fcc7f425b81b9df7c8a8719ed90953b938cd10e"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Sun Apr 19 21:47:56 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Sun Apr 19 21:47:56 2026 +0200"
      },
      "message": "updated releasing.md\n"
    },
    {
      "commit": "7fcc7f425b81b9df7c8a8719ed90953b938cd10e",
      "tree": "75e38d2c016816d246f369de3640ab0013e3e00c",
      "parents": [
        "e2f4ff4d5ee5ea95e15cf4cdb8ff2923d5225fb9"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "43271715+FreeAndNil@users.noreply.github.com",
        "time": "Thu Apr 16 18:14:27 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Apr 16 18:14:27 2026 +0200"
      },
      "message": "preserve UTF-16 surrogate pairs in MaskXmlInvalidCharacters - fixes #290 (#291)\n\nThe regex [^\\x09\\x0A\\x0D\\x20-\\uD7FF\\uE000-\\uFFFD] operated on individual\nUTF-16 char units, causing both halves of a valid surrogate pair to be\nreplaced, silently corrupting supplementary characters (U+10000–U+10FFFF)\nsuch as emoji in XML log output.\n\nFix by prepending a surrogate-pair alternative to the regex so valid pairs\nare matched and preserved as a unit; only lone surrogates and other\nXML-illegal code units are replaced with the mask string.\n\nAlso optimise CountSubstrings: use a char loop for single-character\nsubstrings (all current callers) and StringComparison.Ordinal for the\nmulti-character CDATA token path.\n\nAdd unit tests covering surrogate pair preservation, lone surrogates,\nand CountSubstrings edge cases."
    },
    {
      "commit": "e2f4ff4d5ee5ea95e15cf4cdb8ff2923d5225fb9",
      "tree": "0ac05b301a22cd07f7766e77dca51638b34be4f3",
      "parents": [
        "0b6e500808f704fee0981b5c9fd1e9fef4881cac"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Thu Apr 16 16:44:07 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Thu Apr 16 16:44:07 2026 +0200"
      },
      "message": "add copilot instructions\n"
    },
    {
      "commit": "0b6e500808f704fee0981b5c9fd1e9fef4881cac",
      "tree": "b75bef802b8671c6b563864492ba853f3f6e4530",
      "parents": [
        "592d18de651ebd330416ea68851c145660b68dc0"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "43271715+FreeAndNil@users.noreply.github.com",
        "time": "Tue Apr 14 20:54:55 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Apr 14 20:54:55 2026 +0200"
      },
      "message": "bump internal log4net version for https://github.com/advisories/GHSA-4f7c-pmjv-c25w #289 (#289)"
    },
    {
      "commit": "592d18de651ebd330416ea68851c145660b68dc0",
      "tree": "a139ddc4107ab64d2d96bd9931325114e210494b",
      "parents": [
        "69bb9f4368fdd39114da217beb670bdd2af856f4"
      ],
      "author": {
        "name": "Abdullah hamza",
        "email": "bdh118551@gmail.com",
        "time": "Fri Apr 10 10:35:51 2026 +0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Apr 10 09:35:51 2026 +0200"
      },
      "message": "Reduce silent log event loss during XmlConfigurator reconfiguration (#287)\n\n* feat(Logger): add ReplaceAppenders for atomic appender swap\n\nAdd method to atomically replace all appenders with a new collection.\n\n* Enable diagnostics by resetting Emfix(Hierarchy): reset EmittedNoAppenderWarning in XmlConfigurator\n\nReset the warning flag to allow diagnostics during reconfiguration.\n\n* fix(XmlHierarchyConfigurator): collect appenders before swap to minimize null window\n\nPreviously, ParseChildrenOfLoggerElement called RemoveAllAppenders()\nbefore adding new ones one-by-one, creating a window (equal to the full\nXML parse duration, typically 10-50 ms) during which the logger had no\nappenders and log events were silently dropped.\n\nThis change resolves the race by:\n1. Collecting all incoming appenders into a local List\u003cIAppender\u003e first.\n2. Calling Logger.ReplaceAppenders() to perform the swap in a single\n   writer lock, reducing the zero-appender window to microseconds.\n\n* Fix: resolve flaky SmtpPickupDirAppenderTest.TestOutputContainsSentDate in CI"
    },
    {
      "commit": "69bb9f4368fdd39114da217beb670bdd2af856f4",
      "tree": "f4004d4425c5601818b94d32c1bb59a3c4f22bbf",
      "parents": [
        "103fd9da4b9aee5f0fb6853a2d055c66863e68fc"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Thu Apr 09 23:40:06 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Thu Apr 09 23:40:06 2026 +0200"
      },
      "message": "added release note for #287\n"
    },
    {
      "commit": "103fd9da4b9aee5f0fb6853a2d055c66863e68fc",
      "tree": "c1a187779504a4a17f96e18719f296d14e34ef30",
      "parents": [
        "7661c5d92a109ad546152cf52335b569276d59f8"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Apr 01 14:03:22 2026 +0200"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Wed Apr 01 14:03:22 2026 +0200"
      },
      "message": "Add initial AGENTS.md for AI-assisted vulnerability research\n"
    },
    {
      "commit": "7661c5d92a109ad546152cf52335b569276d59f8",
      "tree": "293922c810bd4903199797342ef1ad2b632977b1",
      "parents": [
        "6e7167c647e29cf61a906905017c2b913ce4a26a"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Fri Mar 27 10:16:57 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Mar 27 10:16:57 2026 +0100"
      },
      "message": "Bump handlebars from 4.7.8 to 4.7.9 (#286)\n\nBumps [handlebars](https://github.com/handlebars-lang/handlebars.js) from 4.7.8 to 4.7.9.\n- [Release notes](https://github.com/handlebars-lang/handlebars.js/releases)\n- [Changelog](https://github.com/handlebars-lang/handlebars.js/blob/v4.7.9/release-notes.md)\n- [Commits](https://github.com/handlebars-lang/handlebars.js/compare/v4.7.8...v4.7.9)\n\n---\nupdated-dependencies:\n- dependency-name: handlebars\n  dependency-version: 4.7.9\n  dependency-type: indirect\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "6e7167c647e29cf61a906905017c2b913ce4a26a",
      "tree": "80377f57fa4cb6ae949df6aef2ac41887f81c307",
      "parents": [
        "11e68f8839d8c70701a14b669e8a8f681b9f99c2"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Thu Mar 26 21:38:07 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Mar 26 21:38:07 2026 +0100"
      },
      "message": "Bump convict from 6.2.4 to 6.2.5 (#285)\n\nBumps [convict](https://github.com/mozilla/node-convict) from 6.2.4 to 6.2.5.\n- [Changelog](https://github.com/mozilla/node-convict/blob/master/CHANGELOG.md)\n- [Commits](https://github.com/mozilla/node-convict/commits)\n\n---\nupdated-dependencies:\n- dependency-name: convict\n  dependency-version: 6.2.5\n  dependency-type: indirect\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "11e68f8839d8c70701a14b669e8a8f681b9f99c2",
      "tree": "66c285137aba7f7cae54c68d4c9a3de5f55505ad",
      "parents": [
        "867930d8ee5c11139e82e996b47a1aeb3ceb405e"
      ],
      "author": {
        "name": "dependabot[bot]",
        "email": "49699333+dependabot[bot]@users.noreply.github.com",
        "time": "Thu Mar 26 08:44:50 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Mar 26 08:44:50 2026 +0100"
      },
      "message": "Bump picomatch (#284)\n\nBumps  and [picomatch](https://github.com/micromatch/picomatch). These dependencies needed to be updated together.\n\nUpdates `picomatch` from 2.3.1 to 2.3.2\n- [Release notes](https://github.com/micromatch/picomatch/releases)\n- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)\n- [Commits](https://github.com/micromatch/picomatch/compare/2.3.1...2.3.2)\n\nUpdates `picomatch` from 4.0.3 to 4.0.4\n- [Release notes](https://github.com/micromatch/picomatch/releases)\n- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)\n- [Commits](https://github.com/micromatch/picomatch/compare/2.3.1...2.3.2)\n\n---\nupdated-dependencies:\n- dependency-name: picomatch\n  dependency-version: 2.3.2\n  dependency-type: indirect\n- dependency-name: picomatch\n  dependency-version: 4.0.4\n  dependency-type: indirect\n...\n\nSigned-off-by: dependabot[bot] \u003csupport@github.com\u003e\nCo-authored-by: dependabot[bot] \u003c49699333+dependabot[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "867930d8ee5c11139e82e996b47a1aeb3ceb405e",
      "tree": "b87cacd789c928f141ebb7489a692e260671346b",
      "parents": [
        "01a0d6e35f9e7e89b17ebbd207c6dd75f7ec372d"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Sat Feb 28 18:15:15 2026 +0100"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Sat Feb 28 18:15:34 2026 +0100"
      },
      "message": "Bump minimatch from 3.1.2 to 3.1.5\n"
    },
    {
      "commit": "01a0d6e35f9e7e89b17ebbd207c6dd75f7ec372d",
      "tree": "5735d76590e63a38c02f0ea9eaccebd701420f8d",
      "parents": [
        "edd722b4ed34811658b782e65a89733cfb12c423"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "43271715+FreeAndNil@users.noreply.github.com",
        "time": "Fri Feb 20 16:02:04 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Feb 20 16:02:04 2026 +0100"
      },
      "message": "#281 fix hints and warnings (#281)\n\n* #281 fix hints and warnings\n* #281 simplify type names"
    },
    {
      "commit": "edd722b4ed34811658b782e65a89733cfb12c423",
      "tree": "a092327fd83ee5c5d224632de9770fb38a06c617",
      "parents": [
        "0fcbd2b1927b6f248026b7b7f47f52f38c2b9677"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Fri Feb 20 14:07:09 2026 +0100"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Fri Feb 20 14:07:09 2026 +0100"
      },
      "message": "bump version to 3.3.1\n"
    },
    {
      "commit": "0fcbd2b1927b6f248026b7b7f47f52f38c2b9677",
      "tree": "4d73a7e20b996af198e13b290b77fdb1bda81c3a",
      "parents": [
        "42a77cb05abfd5b1ad7224f0861a932eac95c7c8"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Feb 17 10:43:39 2026 +0100"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Feb 17 10:43:39 2026 +0100"
      },
      "message": "update release date\n"
    },
    {
      "commit": "42a77cb05abfd5b1ad7224f0861a932eac95c7c8",
      "tree": "a980839d84753d328e81b9e7af517bd2da1c54c8",
      "parents": [
        "10647645458a0ccce9ebbc5b0fa9b6b42b55332d"
      ],
      "author": {
        "name": "Jan Friedrich",
        "email": "freeandnil@apache.org",
        "time": "Tue Feb 17 08:59:08 2026 +0100"
      },
      "committer": {
        "name": "Jan Friedrich",
        "email": "43271715+FreeAndNil@users.noreply.github.com",
        "time": "Tue Feb 17 10:03:55 2026 +0100"
      },
      "message": "#280 harden the handling of invalid characters for the XmlLayout classes\n"
    }
  ],
  "next": "10647645458a0ccce9ebbc5b0fa9b6b42b55332d"
}
