Venafi Issue – Certs Immediately Revoked as Superseded When Using Stand-Alone Microsoft AD CS CA

Background:

Environment

  • Dev environment, Venafi 25.3.0.2740
  • Microsoft ADCS stand-alone CA
  • Enrollment method: DCOM
  • CA object uses a local account on the ADCS server
  • No custom workflows
  • No customizations
  • No consumers/app installation tied to the cert object
  • Simple certificate object created for testing

Problem

When a certificate is requested from Venafi against the stand-alone Microsoft CA, ADCS successfully issues the certificate, but the certificate is immediately revoked with revocation reason:

  • Superseded

This is happening to the same certificate that was just issued, not a prior cert.

Expected behavior

Venafi should submit the CSR, obtain the issued certificate, and leave the newly issued certificate valid.

Actual behavior

Venafi submits the CSR, ADCS issues the certificate successfully, and then the same certificate is immediately revoked as Superseded.

Evidence gathered

1. ADCS database confirms issued cert is the same cert being revoked

Example request:

  • Request ID: 41
  • Requester Name: HOSTNAME\venafi
  • Common Name: 20260331-withrevoke.example.com
  • Serial Number: 55000000299749d000d299f5ae000100000029
  • Disposition: Revoked
  • Disposition Message: Revoked by HOSTNAME\venafi
  • Revocation Reason: 0x4 — Superseded

This proves Venafi is revoking the cert it just obtained.

2. ADCS request contents are valid

For the same request, ADCS shows the CSR and issued certificate are normal and match expectations.

Request attributes

  • CertificateTemplate: WebServer
  • ccm: venafihost.servers.example.com

CSR / issued cert contents

  • Subject: CN=20260331-withrevoke.example.com, O=”Uniti Group, Inc”, L=Little Rock, S=Arkansas, C=US
  • SAN: DNS Name=20260331-withrevoke.example.com
  • RSA 2048 key
  • Certificate issued successfully before revoke

This suggests the CA is not returning malformed or obviously incorrect cert content.

3. Security event log confirms immediate issue then revoke

After enabling Certification Services auditing, Security log shows this sequence:

Event 4886

  • Certificate Services received the request

Event 4887

  • Certificate Services approved the request and issued the certificate
  • Requester: HOSTNAME\venafi
  • DCOM/RPC authentication path used
  • Template shown as WebServer

Event 4870

  • Certificate Services revoked the certificate
  • Same serial number as the issued certificate
  • Reason: 4 (Superseded)

This happens effectively immediately.

4. Pattern is repeatable

Querying the CA database for requests from HOSTNAME\venafi shows a repeated pattern where most requests are immediately revoked with:

  • Disposition: Revoked
  • Revocation Reason: Superseded
  • Disposition Message: Revoked by HOSTNAME\venafi

The exceptions were tests where revoke capability had been intentionally removed from the Venafi CA account.

5. Permission test changed behavior but did not fix root cause

When Issue and Manage Certificates was removed from the Venafi CA account, the request no longer completed the revoke path and instead failed earlier with:

  • PostCSR failed with error: CCertAdmin::SetCertificateExtension: Access is denied. 0x80070005

This indicates Venafi is performing CA administrative operations after CSR submission, and revocation happens later in that same general post-issuance path.

6. Procmon on the Venafi host shows VPlatform.exe using both CertRequest and CertAdmin

Procmon on CWWAPP1989D captured VPlatform.exe doing the following:

Cert enrollment path

VPlatform.exe queries and activates:

  • HKCR\CLSID\{98AFF3F0-5524-11D0-8812-00A0C903B83C}
  • CertRequest Class
  • C:\Windows\System32\certcli.dll

CA admin path

VPlatform.exe then queries and activates:

  • HKCR\CLSID\{37EABAF0-7FB6-11D0-8817-00A0C903B83C}
  • CertAdmin Class
  • %systemroot%\system32\certadm.dll

DCOM/RPC communication

Procmon also shows:

  • endpoint mapper (135) traffic via svchost.exe
  • VPlatform.exe connecting to the CA host on dynamic RPC port 50014

This strongly suggests:

  • VPlatform.exe first issues via CertRequest
  • then immediately performs CA admin operations via CertAdmin

Given the ADCS security logs, that admin path appears to be what revokes the newly issued cert.

Additional observations

Stand-alone CA

This is a stand-alone Microsoft CA, not enterprise template-based ADCS.

No special Venafi workflow/customization

This is a dev system with:

  • no custom workflows
  • no special consumers
  • no installation/application integration
  • minimal test object

That makes this look less like an environmental customization problem and more like:

  • default Venafi behavior in this integration path, or
  • a product defect in the stand-alone Microsoft CA DCOM path

Failed auth events also observed

We saw Security log 4625 failures from CWWAPP1989D for WINDSTREAM\g9897431.

From the Security log:

  • 11:53:34 — 4886 request received
  • 11:53:36 — 4887 certificate issued
  • 11:53:36 — 4870 certificate revoked
  • 11:53:36 — multiple 4625 failures for DOMAIN\venafisystemuser
  • 11:53:37 — another 4625

Since time resolution in the log is seconds, it is possible Venafi is requesting the cert under the configured credential (HOSTNAME\venafi), attempting to do something else under DOMAIN\venafisystemuser, getting an auth failure, and then revoking the certificate under the configured credential (DOMAIN\venafisystemuser). I would be surprised if this is the case because “superseded” is a very specific revocation reason. I would expect something like a generic “Unspecified” or “Cessation of Operation” to be used.

Summary conclusion

Current evidence indicates that:

  • Venafi successfully enrolls the certificate from the stand-alone Microsoft CA using DCOM / CertRequest
  • VPlatform.exe then immediately invokes the Microsoft CA admin COM interface (CertAdmin)
  • the newly issued certificate is then revoked by the Venafi CA account with reason Superseded

At this point, this appears to be:

  • Venafi-driven post-issuance behavior
  • not spontaneous ADCS behavior
  • and likely either:
    1. expected-but-unwanted default behavior in this integration mode, or
    2. a product defect in the stand-alone Microsoft CA DCOM workflow

Resolution

The issue was resolved by changing the policy module settings to set the cert request to pending instead of automatically issue. While I expected this to leave the cert in a pending state and require manual intervention (or a batch job to bulk approve whatever is pending), the cert was immediately issued.

 

Buzzards on the Roof

The buzzards used to hang out in this old, dead tree across the street; and, after the rain, they would spread their wings and dry out. The tree fell a while ago; but, now that our roof is stable … we’ve got buzzards airing out their wings on the roof.

Blender API: List All Items in a Collection

Instead of iterating through all objects, you can iterate through the items in a specific collection:

import bpy

# Name of the collection to inspect
collection_name = "TestCollection"

collection = bpy.data.collections.get(collection_name)

if collection is None:
    print(f"Collection '{collection_name}' not found.")
else:
    print(f"Objects in collection '{collection_name}':")
    for obj in collection.objects:
        print(f"- {obj.name}")

Printing to the console:

For this sample workspace that contains a torus and sphere with the default names

Blender API: Finding The Orange Dot

A quick script to get each object and the location of the “orange dot” … the origin of the object

# Get location of orange dot for each object in Blender
import bpy

scene = bpy.context.scene
us = scene.unit_settings

unit_system = getattr(us, "system", "NONE")  # 'NONE', 'METRIC', 'IMPERIAL'

meters_per_bu = us.scale_length if unit_system != 'NONE' else 1.0
mm_per_bu = meters_per_bu * 1000.0

for obj in bpy.data.objects:
    if obj.type != 'MESH':
        continue

    origin_world = obj.matrix_world.translation          # in BU
    origin_world_mm = origin_world * mm_per_bu           # in mm

    print(f"Object: {obj.name}")
    print(f"  origin_world (BU): {origin_world.x:.6f}, {origin_world.y:.6f}, {origin_world.z:.6f}")
    print(f"  origin_world (mm): {origin_world_mm.x:.3f}, {origin_world_mm.y:.3f}, {origin_world_mm.z:.3f}")
    print("-" * 30)

Blender API: Bending a 2D Rectangle

Another attempt to create a t-post bracket using a script. This creates a 2D rectangle, bends it, and then solidifies it into a 3d object.

import bpy
import bmesh
import math
from mathutils import Vector, Matrix

# -----------------------------
# Reset / clear scene
# -----------------------------
for obj in list(bpy.data.objects):
    bpy.data.objects.remove(obj, do_unlink=True)

# -----------------------------
# Scene units: mm (1 BU = 1 mm)
# -----------------------------
scene = bpy.context.scene
scene.unit_settings.system = 'METRIC'
scene.unit_settings.scale_length = 0.001

INCH_TO_MM = 25.4
def inch(x):  # returns mm (Blender units)
    return x * INCH_TO_MM

# -----------------------------
# Parameters
# -----------------------------
size_x_in = 3.0
size_y_in = 7.0
thickness_in = 0.25  # SOLIDIFY thickness

fold1_offset_in = 0.5   # from MIN-Y end
fold2_offset_in = 2.0   # from MIN-Y end

fold1_rad = math.radians(-80.0)
fold2_rad = math.radians(80.0)

subdivide_cuts = 60
EPS_Y = 1e-5  # mm tolerance for "on the fold line"

# -----------------------------
# Create flat sheet (plane)
# -----------------------------
bpy.ops.mesh.primitive_plane_add(size=1.0, location=(0.0, 0.0, 0.0))
obj = bpy.context.active_object
obj.name = "Bracket"
obj.dimensions = (inch(size_x_in), inch(size_y_in), 0.0)
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)

# Subdivide for clean fold lines
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.subdivide(number_cuts=subdivide_cuts)
bpy.ops.object.mode_set(mode='OBJECT')

# Compute fold Y positions
half_y = inch(size_y_in) / 2.0
min_y = -half_y
y_fold1 = min_y + inch(fold1_offset_in)
y_fold2 = min_y + inch(fold2_offset_in)

# Add both fold lines
bm = bmesh.new()
bm.from_mesh(obj.data)

for y_fold in (y_fold1, y_fold2):
    geom = bm.verts[:] + bm.edges[:] + bm.faces[:]
    bmesh.ops.bisect_plane(
        bm,
        geom=geom,
        plane_co=Vector((0.0, y_fold, 0.0)),
        plane_no=Vector((0.0, 1.0, 0.0)),
        clear_inner=False,
        clear_outer=False
    )

bm.normal_update()
bm.to_mesh(obj.data)
bm.free()

# -----------------------------
# Re-open bmesh, store ORIGINAL Y per vertex
# -----------------------------
bm = bmesh.new()
bm.from_mesh(obj.data)
bm.verts.ensure_lookup_table()

orig_y_layer = bm.verts.layers.float.new("orig_y")
for v in bm.verts:
    v[orig_y_layer] = v.co.y

# ============================================================
# FOLD 1
# ============================================================
hinge_verts_1 = [v for v in bm.verts if abs(v[orig_y_layer] - y_fold1) < EPS_Y]
if not hinge_verts_1:
    raise RuntimeError("No hinge vertices found for fold 1. Increase subdivide_cuts or EPS_Y.")

hinge_point_1 = Vector((0.0, 0.0, 0.0))
for v in hinge_verts_1:
    hinge_point_1 += v.co
hinge_point_1 /= len(hinge_verts_1)

verts_to_rotate_1 = [v for v in bm.verts if v[orig_y_layer] > (y_fold1 + EPS_Y)]
rot1 = Matrix.Rotation(fold1_rad, 4, 'X')
bmesh.ops.rotate(bm, verts=verts_to_rotate_1, cent=hinge_point_1, matrix=rot1)

# ============================================================
# FOLD 2
# ============================================================
hinge_verts_2 = [v for v in bm.verts if abs(v[orig_y_layer] - y_fold2) < EPS_Y]
if not hinge_verts_2:
    raise RuntimeError("No hinge vertices found for fold 2. Increase subdivide_cuts or EPS_Y.")

hinge_point_2 = Vector((0.0, 0.0, 0.0))
for v in hinge_verts_2:
    hinge_point_2 += v.co
hinge_point_2 /= len(hinge_verts_2)

verts_to_rotate_2 = [v for v in bm.verts if v[orig_y_layer] > (y_fold2 + EPS_Y)]
rot2 = Matrix.Rotation(fold2_rad, 4, 'X')
bmesh.ops.rotate(bm, verts=verts_to_rotate_2, cent=hinge_point_2, matrix=rot2)

# Write back mesh
bm.normal_update()
bm.to_mesh(obj.data)
bm.free()

# -----------------------------
# Solidify AFTER folding
# -----------------------------
solid = obj.modifiers.new(name="Solidify_0p5in", type='SOLIDIFY')
solid.thickness = inch(thickness_in)  # 0.5"
solid.offset = 0.0                    # centered thickness (equal on both sides)
solid.use_even_offset = True
solid.use_rim = True

# Optional: keep object active
bpy.ops.object.select_all(action='DESELECT')
obj.select_set(True)
bpy.context.view_layer.objects.active = obj

Blender API: Playing with Cylinders

This script was mostly made to play around with rotation on cylinders.

import bpy
import math

# Delete all existing objects
for obj in list(bpy.data.objects):
    bpy.data.objects.remove(obj, do_unlink=True)

for i in range(4):
    bpy.ops.mesh.primitive_cylinder_add(
        radius=0.5,
        depth=10.0,
        location=(0, 0.0, 0.0),
        rotation=((i * 5.5), 0.0, 0.0)
    )

    cyl = bpy.context.active_object
    cyl.name = f"DemoCylinderX{i}"

for i in range(4):
    bpy.ops.mesh.primitive_cylinder_add(
        radius=0.5,
        depth=10.0,
        location=(0, 0.0, 0.0),
        rotation=(0.0, (i * 5.5), 0.0)
    )

    cyl = bpy.context.active_object
    cyl.name = f"DemoCylinderY{i}"

# cyl.rotation_euler = (15.0,13.0,12.0)

# Or single-axis rotation
# Rotate 45 degrees about X axis
#cyl.rotation_euler[0] = math.radians(45.0)


Querying the RPC Endpoint Mapper

A lot of RPC services start out on a standard port (TCP port 135) and then move over to a dynamically allocated port. Fortunately, there’s a way to ask the RPC endpoint mapper what services are available and what port(s) have been assigned to that service. It uses the portqry command:

C:\PortQryV2>portqry -n host2043.servers.example.com -e 135 -p tcp -v

Note: the -v option only displays extra data in local mode

Querying target system called:

 host2043.servers.example.com

Attempting to resolve name to IP address...


Name resolved to 10.237.73.103

querying...

TCP port 135 (epmap service): LISTENING

Using ephemeral source port
Querying Endpoint Mapper Database...
Server's response:

UUID: 04eeb297-cbf4-466b-8a2a-bfd6a2f10bba EFSK RPC Interface
ncacn_np:host2043.servers.example.com[\\pipe\\efsrpc]

UUID: 367abb81-9844-35f1-ad32-98f038001003
ncacn_ip_tcp:host2043.servers.example.com[50007]

UUID: 91ae6020-9e3c-11cf-8d7c-00aa00c091be
ncacn_np:host2043.servers.example.com[\\pipe\\cert]

UUID: 91ae6020-9e3c-11cf-8d7c-00aa00c091be
ncacn_ip_tcp:host2043.servers.example.com[50006]

UUID: 29770a8f-829b-4158-90a2-78cd488501f7
ncacn_np:host2043.servers.example.com[\\pipe\\SessEnvPublicRpc]

UUID: 29770a8f-829b-4158-90a2-78cd488501f7
ncacn_ip_tcp:host2043.servers.example.com[50004]

UUID: 7f1343fe-50a9-4927-a778-0c5859517bac DfsDs service
ncacn_np:host2043.servers.example.com[\\PIPE\\wkssvc]

UUID: f6beaff7-1e19-4fbb-9f8f-b89e2018337c Windows Event Log
ncacn_np:host2043.servers.example.com[\\pipe\\eventlog]

UUID: f6beaff7-1e19-4fbb-9f8f-b89e2018337c Windows Event Log
ncacn_ip_tcp:host2043.servers.example.com[50002]

UUID: 1ff70682-0a51-30e8-076d-740be8cee98b
ncacn_np:host2043.servers.example.com[\\PIPE\\atsvc]

UUID: 378e52b0-c0a9-11cf-822d-00aa0051e40f
ncacn_np:host2043.servers.example.com[\\PIPE\\atsvc]

UUID: 33d84484-3626-47ee-8c6f-e7e98b113be1
ncacn_np:host2043.servers.example.com[\\PIPE\\atsvc]

UUID: 86d35949-83c9-4044-b424-db363231fd0c
ncacn_np:host2043.servers.example.com[\\PIPE\\atsvc]

UUID: 86d35949-83c9-4044-b424-db363231fd0c
ncacn_ip_tcp:host2043.servers.example.com[50003]

UUID: 3a9ef155-691d-4449-8d05-09ad57031823
ncacn_np:host2043.servers.example.com[\\PIPE\\atsvc]

UUID: 3a9ef155-691d-4449-8d05-09ad57031823
ncacn_ip_tcp:host2043.servers.example.com[50003]

UUID: c9ac6db5-82b7-4e55-ae8a-e464ed7b4277 Impl friendly name
ncacn_hvsocket:host2043.servers.example.com[F58797F6-C9F3-4D63-9BD4-E52AC020E586]

UUID: 76f226c3-ec14-4325-8a99-6a46348418af
ncacn_np:host2043.servers.example.com[\\PIPE\\InitShutdown]

UUID: d95afe70-a6d5-4259-822e-2c84da1ddb0d
ncacn_np:host2043.servers.example.com[\\PIPE\\InitShutdown]

UUID: d95afe70-a6d5-4259-822e-2c84da1ddb0d
ncacn_ip_tcp:host2043.servers.example.com[50001]

UUID: 12345778-1234-abcd-ef00-0123456789ac
ncacn_np:host2043.servers.example.com[\\pipe\\lsass]

UUID: 12345778-1234-abcd-ef00-0123456789ac
ncacn_ip_tcp:host2043.servers.example.com[50000]

UUID: 0b1c2170-5732-4e0e-8cd3-d9b16f3b84d7 RemoteAccessCheck
ncacn_np:host2043.servers.example.com[\\pipe\\lsass]

UUID: 0b1c2170-5732-4e0e-8cd3-d9b16f3b84d7 RemoteAccessCheck
ncacn_ip_tcp:host2043.servers.example.com[50000]

UUID: 0b1c2170-5732-4e0e-8cd3-d9b16f3b84d7 RemoteAccessCheck
ncacn_ip_tcp:host2043.servers.example.com[50005]

UUID: 0b1c2170-5732-4e0e-8cd3-d9b16f3b84d7 RemoteAccessCheck
ncacn_np:host2043.servers.example.com[\\pipe\\lsass]

UUID: 0b1c2170-5732-4e0e-8cd3-d9b16f3b84d7 RemoteAccessCheck
ncacn_ip_tcp:host2043.servers.example.com[50000]

UUID: 0b1c2170-5732-4e0e-8cd3-d9b16f3b84d7 RemoteAccessCheck
ncacn_ip_tcp:host2043.servers.example.com[50005]

UUID: b25a52bf-e5dd-4f4a-aea6-8ca7272a0e86 KeyIso
ncacn_np:host2043.servers.example.com[\\pipe\\lsass]

UUID: b25a52bf-e5dd-4f4a-aea6-8ca7272a0e86 KeyIso
ncacn_ip_tcp:host2043.servers.example.com[50000]

UUID: b25a52bf-e5dd-4f4a-aea6-8ca7272a0e86 KeyIso
ncacn_ip_tcp:host2043.servers.example.com[50005]

UUID: 8fb74744-b2ff-4c00-be0d-9ef9a191fe1b Ngc Pop Key Service
ncacn_np:host2043.servers.example.com[\\pipe\\lsass]

UUID: 8fb74744-b2ff-4c00-be0d-9ef9a191fe1b Ngc Pop Key Service
ncacn_ip_tcp:host2043.servers.example.com[50000]

UUID: 8fb74744-b2ff-4c00-be0d-9ef9a191fe1b Ngc Pop Key Service
ncacn_ip_tcp:host2043.servers.example.com[50005]

UUID: 51a227ae-825b-41f2-b4a9-1ac9557a1018 Ngc Pop Key Service
ncacn_np:host2043.servers.example.com[\\pipe\\lsass]

UUID: 51a227ae-825b-41f2-b4a9-1ac9557a1018 Ngc Pop Key Service
ncacn_ip_tcp:host2043.servers.example.com[50000]

UUID: 51a227ae-825b-41f2-b4a9-1ac9557a1018 Ngc Pop Key Service
ncacn_ip_tcp:host2043.servers.example.com[50005]

UUID: df1941c5-fe89-4e79-bf10-463657acf44d EFS RPC Interface
ncacn_np:host2043.servers.example.com[\\pipe\\efsrpc]

Total endpoints found: 38



==== End of RPC Endpoint Mapper query response ====




Blender Scripting Lesson of the Week: Beveling

We were playing around with bevels this week – it’s pretty straight forward, the API lets you set the parameters you set through the GUI in a bevel modifier.

import bpy

# Clear all existing objects
for obj in list(bpy.data.objects):
    bpy.data.objects.remove(obj, do_unlink=True)

# Set Units
scene = bpy.context.scene
scene.unit_settings.system = 'METRIC'
scene.unit_settings.scale_length = 0.001  # 1 BU = 1 mm

# Create rectangular cube
bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0))
block = bpy.context.active_object
block.name = "Block"

# cube default size is 2x2x2, so set absolute dimensions
block.dimensions = (2.0, 20.0, 0.25)
bpy.context.view_layer.objects.active = block
block.select_set(True)

# Apply scale so booleans/bevel behave predictably
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)

# Create cylinder cutter
hole_diameter = 1.0
hole_radius = hole_diameter / 2.0

# Make it longer than the block thickness so it fully cuts through
cutter_depth = 5.0

bpy.ops.mesh.primitive_cylinder_add(
    vertices=64,
    radius=hole_radius,
    depth=cutter_depth,
    location=(0.0, 0.0, 0.0),   # center of the block
    rotation=(0.0, 0.0, 0.0)
)
cutter = bpy.context.active_object
cutter.name = "HoleCutter"

bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)

# Boolean: cut hole
bpy.context.view_layer.objects.active = block
bool_mod = block.modifiers.new(name="Hole", type='BOOLEAN')
bool_mod.operation = 'DIFFERENCE'
bool_mod.solver = 'EXACT'
bool_mod.object = cutter

# Apply boolean
bpy.ops.object.modifier_apply(modifier=bool_mod.name)

# Hide cutter in viewport + renders
cutter.hide_set(True)
cutter.hide_render = True

# Bevel the block
bevel_width = 0.08 
bevel_segments = 5

bevel_mod = block.modifiers.new(name="Bevel", type='BEVEL')
bevel_mod.width = bevel_width
bevel_mod.segments = bevel_segments
bevel_mod.limit_method = 'ANGLE'
bevel_mod.angle_limit = 0.523599  # 30 degrees in radians

# Apply bevel
bpy.ops.object.modifier_apply(modifier=bevel_mod.name)